summaryrefslogtreecommitdiff
path: root/why-rust.md
diff options
context:
space:
mode:
Diffstat (limited to 'why-rust.md')
-rw-r--r--why-rust.md236
1 files changed, 236 insertions, 0 deletions
diff --git a/why-rust.md b/why-rust.md
new file mode 100644
index 0000000..b166f03
--- /dev/null
+++ b/why-rust.md
@@ -0,0 +1,236 @@
+---
+title: "Why Rust?"
+author: Lars Wirzenius
+...
+
+# About me
+
+* First learnt programming in April, 1984, so 36 years ago
+* Been programming more or less daily ever since
+* BASIC, Pascal, C, a little C++, Unix shell, AWK, a lot of Python, Lisp, a
+ little Haskell, a little Go, and now Rust
+* I really like Rust
+* Rust is like Haskell and C had a love child with unicorn fairy godmothers
+
+---
+
+# Why I like Rust: type system
+
+* strong, static, versatile typing
+
+ - helps avoid many bugs, reduces need to test every statement and
+ branch with unit tests
+ - not quite true that if a program compiles, it works, but Rust is a
+ lot closer to that than C, C++, Pascal, etc
+ - avoids entire classes of bugs: NULL pointer errors, unchecked
+ error returns, implicit but wrong value conversions
+
+* type inference: mostly only need to specify function signatures,
+ structs, and similar parts and the compiler deduces the rest
+
+---
+
+# Why I like Rust: memory management
+
+* manual, a la C: malloc, free
+
+ - error prone: easy to leak (no free), easy to break (more than one
+ free), hard to debug
+
+* automatic, with garbage collection
+
+ - Lisp, Python, Go
+ - requires a runtime
+ - despite decades of research, inevitably there is overhead and
+ short pauses
+
+* Rust: automatic with borrow checker, lifetimes
+
+ - all heap values heap are tied to values on the stack
+ - when on-stack value is freed, the heap value is dropped
+ - requires making sure stack values have the right lifetimes
+ - mutability must be declared explicitly
+ - compiler can prove lack of data races
+
+---
+
+# Why I like Rust: misc
+
+* not controlled by a megacorporation
+* the ? operator and the Result type
+* the Option type
+* enums are powerful
+* pattern matching is powerful and exhaustive
+* no OOP, but traits
+* zero cost abstractions actually work
+* binaries execute quickly
+* excellent concurrency support
+
+---
+
+# Why I like Rust: tooling and ecosystem
+
+* cargo, crates.io work well and avoid most pitfalls other languages
+ have
+* good doctests
+* things get better, the community and ecosystem seem lively
+* avoids the 20/80 principle: problems are solved well, "pragmatic
+ shortcuts" to allow implementation to be simpler are avoided, if the
+ shortcut would be likely to bit users
+* the community is friendly and constructive
+
+---
+
+# Not everything is perfect
+
+* things in the language and important libraries change
+ - but almost always with backwards compatibility)
+* supports a lot fewer targets than C
+ - but the big mainstream ones are supported
+* not well packaged for Linux distros; rustup is needed
+ - bug as the language stabilizes, this will improve
+* de facto static linking only
+ - dynamic linking works, but Rust ABI is not yet stable, so static
+ is the default
+* compilation is somewhat slow
+
+---
+
+# Example: hello
+
+```{.rust .numberLines}
+fn main() {
+ println!("Hello, world!");
+}
+```
+
+---
+
+# Example: Subplot docgen main program
+
+```{.rust .numberLines}
+use chrono::{Local, TimeZone};
+use pandoc;
+use std::fs;
+use std::path::Path;
+use std::path::PathBuf;
+use std::time::UNIX_EPOCH;
+use structopt::StructOpt;
+
+use subplot;
+```
+---
+
+```{.rust .numberLines}
+// Define the command line arguments.
+#[derive(Debug, StructOpt)]
+#[structopt(name = "docgen",
+ about = "Subplot document generator.")]
+struct Opt {
+ // One or more input filename.
+ #[structopt(parse(from_os_str))]
+ filenames: Vec<PathBuf>,
+
+ // Set output file name.
+ #[structopt(name = "FILE", long = "--output",
+ short = "-o", parse(from_os_str))]
+ output: PathBuf,
+
+ // Set date.
+ #[structopt(name = "DATE", long = "--date")]
+ date: Option<String>,
+}
+```
+---
+
+```{.rust .numberLines}
+fn main() -> subplot::Result<()> {
+ let opt = Opt::from_args();
+ let mut pandoc = pandoc::new();
+
+ // Tell Pandoc what the input files are.
+ let first_file = &opt.filenames[0];
+ for filename in opt.filenames.iter() {
+ pandoc.add_input(&filename);
+ }
+```
+---
+
+```{.rust .numberLines}
+ // Tell Pandoc what the input file format is.
+ pandoc.set_input_format(
+ pandoc::InputFormat::Markdown,
+ vec![pandoc::MarkdownExtension::Citations],
+ );
+
+ // Add external Pandoc filters.
+ let citeproc = std::path::Path::new("pandoc-citeproc");
+ pandoc.add_option(
+ pandoc::PandocOption::Filter(
+ citeproc.to_path_buf()));
+
+ // This would be nicer if pandoc took a Pathbuf for output,
+ // instead of a String. Reported as
+ // <https://github.com/oli-obk/rust-pandoc/issues/23>
+ let output = format!("{}", opt.output.display());
+ pandoc.set_output(pandoc::OutputKind::File(output));
+```
+---
+
+```{.rust .numberLines}
+ // Set options for Pandoc.
+ pandoc.add_option(pandoc::PandocOption::TableOfContents);
+ pandoc.add_option(pandoc::PandocOption::Standalone);
+ pandoc.add_option(pandoc::PandocOption::NumberSections);
+```
+---
+
+```{.rust .numberLines}
+ // Metadata date from command line or file mtime. However, we
+ // can't set it directly, since we don't want to override the date
+ // in the actual document, if given, so we only set
+ // user-provided-date. Our parsing code will use that if date is
+ // not document metadata.
+ let date = if let Some(date) = opt.date {
+ date
+ } else {
+ // We have to parse the document to get the date from the
+ // metadata. We can't set the metadata for typesetting until
+ // we do. So we parse it twice.
+ let doc = subplot::Document::from_file(&first_file)?;
+ if let Some(date) = doc.meta().date() {
+ date.to_string()
+ } else {
+ mtime(first_file)?
+ }
+ };
+ pandoc.add_option(pandoc::PandocOption::Meta("date".to_string(), Some(date)));
+```
+---
+
+```{.rust .numberLines}
+ // Run Pandoc to parse the inputs into an abstract syntax tree,
+ // then run our filter on that, then let Pandoc produce the output
+ // file from the AST.
+ pandoc.add_filter(|json| {
+ let mut doc = subplot::Document::from_json(&json).expect("error parsing JSON AST");
+ doc.has_title().expect("document has no title");
+ doc.typeset();
+ doc.ast().expect("error serializing into JSON AST")
+ });
+ pandoc.execute()?;
+
+ Ok(())
+}
+```
+---
+
+```{.rust .numberLines}
+fn mtime(filename: &Path) -> subplot::Result<String> {
+ let mtime = fs::metadata(filename)?.modified()?;
+ let secs = mtime.duration_since(UNIX_EPOCH)?.as_secs();
+ let secs: i64 = format!("{}", secs).parse()?;
+ let dt = Local.timestamp(secs, 0);
+ Ok(dt.format("%Y-%m-%d %H:%M").to_string())
+}
+```