From ef7f833c1fa907223f80a3a4af407cfcb11b38ef Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 12:50:27 -0700 Subject: [PATCH 001/386] Initial --- .gitignore | 1 + _config.yml | 14 ++ _includes/footer.html | 55 +++++ _includes/head.html | 11 + _includes/header.html | 27 +++ _layouts/default.html | 20 ++ _layouts/page.html | 14 ++ _layouts/post.html | 15 ++ _posts/2014-09-08-welcome-to-jekyll.markdown | 25 ++ _sass/_base.scss | 203 ++++++++++++++++ _sass/_layout.scss | 236 +++++++++++++++++++ _sass/_syntax-highlighting.scss | 67 ++++++ about.md | 11 + css/main.scss | 49 ++++ feed.xml | 30 +++ index.html | 23 ++ 16 files changed, 801 insertions(+) create mode 100644 .gitignore create mode 100644 _config.yml create mode 100644 _includes/footer.html create mode 100644 _includes/head.html create mode 100644 _includes/header.html create mode 100644 _layouts/default.html create mode 100644 _layouts/page.html create mode 100644 _layouts/post.html create mode 100644 _posts/2014-09-08-welcome-to-jekyll.markdown create mode 100644 _sass/_base.scss create mode 100644 _sass/_layout.scss create mode 100644 _sass/_syntax-highlighting.scss create mode 100644 about.md create mode 100755 css/main.scss create mode 100644 feed.xml create mode 100644 index.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c08f9add7 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +_site \ No newline at end of file diff --git a/_config.yml b/_config.yml new file mode 100644 index 000000000..2f03e74d4 --- /dev/null +++ b/_config.yml @@ -0,0 +1,14 @@ +# Site settings +title: Your awesome title +email: your-email@domain.com +description: > # this means to ignore newlines until "baseurl:" + Write an awesome description for your new site here. You can edit this + line in _config.yml. It will appear in your document head meta (for + Google search results) and in your feed.xml site description. +baseurl: "" # the subpath of your site, e.g. /blog/ +url: "http://yourdomain.com" # the base hostname & protocol for your site +twitter_username: jekyllrb +github_username: jekyll + +# Build settings +markdown: kramdown diff --git a/_includes/footer.html b/_includes/footer.html new file mode 100644 index 000000000..be3976f7e --- /dev/null +++ b/_includes/footer.html @@ -0,0 +1,55 @@ + diff --git a/_includes/head.html b/_includes/head.html new file mode 100644 index 000000000..ec8f7ca5f --- /dev/null +++ b/_includes/head.html @@ -0,0 +1,11 @@ + + + + + + {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} + + + + + diff --git a/_includes/header.html b/_includes/header.html new file mode 100644 index 000000000..cfe381f75 --- /dev/null +++ b/_includes/header.html @@ -0,0 +1,27 @@ + diff --git a/_layouts/default.html b/_layouts/default.html new file mode 100644 index 000000000..e4ab96fb0 --- /dev/null +++ b/_layouts/default.html @@ -0,0 +1,20 @@ + + + + {% include head.html %} + + + + {% include header.html %} + +
+
+ {{ content }} +
+
+ + {% include footer.html %} + + + + diff --git a/_layouts/page.html b/_layouts/page.html new file mode 100644 index 000000000..74c1a1184 --- /dev/null +++ b/_layouts/page.html @@ -0,0 +1,14 @@ +--- +layout: default +--- +
+ +
+

{{ page.title }}

+
+ +
+ {{ content }} +
+ +
diff --git a/_layouts/post.html b/_layouts/post.html new file mode 100644 index 000000000..a2b4e52fe --- /dev/null +++ b/_layouts/post.html @@ -0,0 +1,15 @@ +--- +layout: default +--- +
+ +
+

{{ page.title }}

+ +
+ +
+ {{ content }} +
+ +
diff --git a/_posts/2014-09-08-welcome-to-jekyll.markdown b/_posts/2014-09-08-welcome-to-jekyll.markdown new file mode 100644 index 000000000..df6a3dc0e --- /dev/null +++ b/_posts/2014-09-08-welcome-to-jekyll.markdown @@ -0,0 +1,25 @@ +--- +layout: post +title: "Welcome to Jekyll!" +date: 2014-09-08 12:48:43 +categories: jekyll update +--- +You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve --watch`, which launches a web server and auto-regenerates your site when a file is updated. + +To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. + +Jekyll also offers powerful support for code snippets: + +{% highlight ruby %} +def print_hi(name) + puts "Hi, #{name}" +end +print_hi('Tom') +#=> prints 'Hi, Tom' to STDOUT. +{% endhighlight %} + +Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll’s dedicated Help repository][jekyll-help]. + +[jekyll]: http://jekyllrb.com +[jekyll-gh]: https://github.com/jekyll/jekyll +[jekyll-help]: https://github.com/jekyll/jekyll-help diff --git a/_sass/_base.scss b/_sass/_base.scss new file mode 100644 index 000000000..d0fa8dcd8 --- /dev/null +++ b/_sass/_base.scss @@ -0,0 +1,203 @@ +/** + * Reset some basic elements + */ +body, h1, h2, h3, h4, h5, h6, +p, blockquote, pre, hr, +dl, dd, ol, ul, figure { + margin: 0; + padding: 0; +} + + + +/** + * Basic styling + */ +body { + font-family: $base-font-family; + font-size: $base-font-size; + line-height: $base-line-height; + font-weight: 300; + color: $text-color; + background-color: $background-color; +} + + + +/** + * Set `margin-bottom` to maintain vertycal rhythm + */ +h1, h2, h3, h4, h5, h6, +p, blockquote, pre, +ul, ol, dl, figure, +%vertical-rhythm { + margin-bottom: $spacing-unit / 2; +} + + + +/** + * Images + */ +img { + max-width: 100%; + vertical-align: middle; +} + + + +/** + * Figures + */ +figure > img { + display: block; +} + +figcaption { + font-size: $small-font-size; +} + + + +/** + * Lists + */ +ul, ol { + margin-left: $spacing-unit; +} + +li { + > ul, + > ol { + margin-bottom: 0; + } +} + + + +/** + * Headings + */ +h1, h2, h3, h4, h5, h6 { + font-weight: 300; +} + + + +/** + * Links + */ +a { + color: $brand-color; + text-decoration: none; + + &:visited { + color: darken($brand-color, 15%); + } + + &:hover { + color: $text-color; + text-decoration: underline; + } +} + + + +/** + * Blockquotes + */ +blockquote { + color: $grey-color; + border-left: 4px solid $grey-color-light; + padding-left: $spacing-unit / 2; + font-size: 18px; + letter-spacing: -1px; + font-style: italic; + + > :last-child { + margin-bottom: 0; + } +} + + + +/** + * Code formatting + */ +pre, +code { + font-size: 15px; + border: 1px solid $grey-color-light; + border-radius: 3px; + background-color: #eef; +} + +code { + padding: 1px 5px; +} + +pre { + padding: 8px 12px; + overflow-x: scroll; + + > code { + border: 0; + padding-right: 0; + padding-left: 0; + } +} + + + +/** + * Wrapper + */ +.wrapper { + max-width: -webkit-calc(800px - (#{$spacing-unit} * 2)); + max-width: calc(800px - (#{$spacing-unit} * 2)); + margin-right: auto; + margin-left: auto; + padding-right: $spacing-unit; + padding-left: $spacing-unit; + @extend %clearfix; + + @include media-query($on-laptop) { + max-width: -webkit-calc(800px - (#{$spacing-unit})); + max-width: calc(800px - (#{$spacing-unit})); + padding-right: $spacing-unit / 2; + padding-left: $spacing-unit / 2; + } +} + + + +/** + * Clearfix + */ +%clearfix { + + &:after { + content: ""; + display: table; + clear: both; + } +} + + + +/** + * Icons + */ +.icon { + + > svg { + display: inline-block; + width: 16px; + height: 16px; + vertical-align: middle; + + path { + fill: $grey-color; + } + } +} diff --git a/_sass/_layout.scss b/_sass/_layout.scss new file mode 100644 index 000000000..def56f896 --- /dev/null +++ b/_sass/_layout.scss @@ -0,0 +1,236 @@ +/** + * Site header + */ +.site-header { + border-top: 5px solid $grey-color-dark; + border-bottom: 1px solid $grey-color-light; + min-height: 56px; + + // Positioning context for the mobile navigation icon + position: relative; +} + +.site-title { + font-size: 26px; + line-height: 56px; + letter-spacing: -1px; + margin-bottom: 0; + float: left; + + &, + &:visited { + color: $grey-color-dark; + } +} + +.site-nav { + float: right; + line-height: 56px; + + .menu-icon { + display: none; + } + + .page-link { + color: $text-color; + line-height: $base-line-height; + + // Gaps between nav items, but not on the first one + &:not(:first-child) { + margin-left: 20px; + } + } + + @include media-query($on-palm) { + position: absolute; + top: 9px; + right: 30px; + background-color: $background-color; + border: 1px solid $grey-color-light; + border-radius: 5px; + text-align: right; + + .menu-icon { + display: block; + float: right; + width: 36px; + height: 26px; + line-height: 0; + padding-top: 10px; + text-align: center; + + > svg { + width: 18px; + height: 15px; + + path { + fill: $grey-color-dark; + } + } + } + + .trigger { + clear: both; + display: none; + } + + &:hover .trigger { + display: block; + padding-bottom: 5px; + } + + .page-link { + display: block; + padding: 5px 10px; + } + } +} + + + +/** + * Site footer + */ +.site-footer { + border-top: 1px solid $grey-color-light; + padding: $spacing-unit 0; +} + +.footer-heading { + font-size: 18px; + margin-bottom: $spacing-unit / 2; +} + +.contact-list, +.social-media-list { + list-style: none; + margin-left: 0; +} + +.footer-col-wrapper { + font-size: 15px; + color: $grey-color; + margin-left: -$spacing-unit / 2; + @extend %clearfix; +} + +.footer-col { + float: left; + margin-bottom: $spacing-unit / 2; + padding-left: $spacing-unit / 2; +} + +.footer-col-1 { + width: -webkit-calc(35% - (#{$spacing-unit} / 2)); + width: calc(35% - (#{$spacing-unit} / 2)); +} + +.footer-col-2 { + width: -webkit-calc(20% - (#{$spacing-unit} / 2)); + width: calc(20% - (#{$spacing-unit} / 2)); +} + +.footer-col-3 { + width: -webkit-calc(45% - (#{$spacing-unit} / 2)); + width: calc(45% - (#{$spacing-unit} / 2)); +} + +@include media-query($on-laptop) { + .footer-col-1, + .footer-col-2 { + width: -webkit-calc(50% - (#{$spacing-unit} / 2)); + width: calc(50% - (#{$spacing-unit} / 2)); + } + + .footer-col-3 { + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + +@include media-query($on-palm) { + .footer-col { + float: none; + width: -webkit-calc(100% - (#{$spacing-unit} / 2)); + width: calc(100% - (#{$spacing-unit} / 2)); + } +} + + + +/** + * Page content + */ +.page-content { + padding: $spacing-unit 0; +} + +.page-heading { + font-size: 20px; +} + +.post-list { + margin-left: 0; + list-style: none; + + > li { + margin-bottom: $spacing-unit; + } +} + +.post-meta { + font-size: $small-font-size; + color: $grey-color; +} + +.post-link { + display: block; + font-size: 24px; +} + + + +/** + * Posts + */ +.post-header { + margin-bottom: $spacing-unit; +} + +.post-title { + font-size: 42px; + letter-spacing: -1px; + line-height: 1; + + @include media-query($on-laptop) { + font-size: 36px; + } +} + +.post-content { + margin-bottom: $spacing-unit; + + h2 { + font-size: 32px; + + @include media-query($on-laptop) { + font-size: 28px; + } + } + + h3 { + font-size: 26px; + + @include media-query($on-laptop) { + font-size: 22px; + } + } + + h4 { + font-size: 20px; + + @include media-query($on-laptop) { + font-size: 18px; + } + } +} diff --git a/_sass/_syntax-highlighting.scss b/_sass/_syntax-highlighting.scss new file mode 100644 index 000000000..e36627da7 --- /dev/null +++ b/_sass/_syntax-highlighting.scss @@ -0,0 +1,67 @@ +/** + * Syntax highlighting styles + */ +.highlight { + background: #fff; + @extend %vertical-rhythm; + + .c { color: #998; font-style: italic } // Comment + .err { color: #a61717; background-color: #e3d2d2 } // Error + .k { font-weight: bold } // Keyword + .o { font-weight: bold } // Operator + .cm { color: #998; font-style: italic } // Comment.Multiline + .cp { color: #999; font-weight: bold } // Comment.Preproc + .c1 { color: #998; font-style: italic } // Comment.Single + .cs { color: #999; font-weight: bold; font-style: italic } // Comment.Special + .gd { color: #000; background-color: #fdd } // Generic.Deleted + .gd .x { color: #000; background-color: #faa } // Generic.Deleted.Specific + .ge { font-style: italic } // Generic.Emph + .gr { color: #a00 } // Generic.Error + .gh { color: #999 } // Generic.Heading + .gi { color: #000; background-color: #dfd } // Generic.Inserted + .gi .x { color: #000; background-color: #afa } // Generic.Inserted.Specific + .go { color: #888 } // Generic.Output + .gp { color: #555 } // Generic.Prompt + .gs { font-weight: bold } // Generic.Strong + .gu { color: #aaa } // Generic.Subheading + .gt { color: #a00 } // Generic.Traceback + .kc { font-weight: bold } // Keyword.Constant + .kd { font-weight: bold } // Keyword.Declaration + .kp { font-weight: bold } // Keyword.Pseudo + .kr { font-weight: bold } // Keyword.Reserved + .kt { color: #458; font-weight: bold } // Keyword.Type + .m { color: #099 } // Literal.Number + .s { color: #d14 } // Literal.String + .na { color: #008080 } // Name.Attribute + .nb { color: #0086B3 } // Name.Builtin + .nc { color: #458; font-weight: bold } // Name.Class + .no { color: #008080 } // Name.Constant + .ni { color: #800080 } // Name.Entity + .ne { color: #900; font-weight: bold } // Name.Exception + .nf { color: #900; font-weight: bold } // Name.Function + .nn { color: #555 } // Name.Namespace + .nt { color: #000080 } // Name.Tag + .nv { color: #008080 } // Name.Variable + .ow { font-weight: bold } // Operator.Word + .w { color: #bbb } // Text.Whitespace + .mf { color: #099 } // Literal.Number.Float + .mh { color: #099 } // Literal.Number.Hex + .mi { color: #099 } // Literal.Number.Integer + .mo { color: #099 } // Literal.Number.Oct + .sb { color: #d14 } // Literal.String.Backtick + .sc { color: #d14 } // Literal.String.Char + .sd { color: #d14 } // Literal.String.Doc + .s2 { color: #d14 } // Literal.String.Double + .se { color: #d14 } // Literal.String.Escape + .sh { color: #d14 } // Literal.String.Heredoc + .si { color: #d14 } // Literal.String.Interpol + .sx { color: #d14 } // Literal.String.Other + .sr { color: #009926 } // Literal.String.Regex + .s1 { color: #d14 } // Literal.String.Single + .ss { color: #990073 } // Literal.String.Symbol + .bp { color: #999 } // Name.Builtin.Pseudo + .vc { color: #008080 } // Name.Variable.Class + .vg { color: #008080 } // Name.Variable.Global + .vi { color: #008080 } // Name.Variable.Instance + .il { color: #099 } // Literal.Number.Integer.Long +} diff --git a/about.md b/about.md new file mode 100644 index 000000000..3ed64bb62 --- /dev/null +++ b/about.md @@ -0,0 +1,11 @@ +--- +layout: page +title: About +permalink: /about/ +--- + +This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/) + +You can find the source code for the Jekyll new theme at: [github.com/jglovier/jekyll-new](https://github.com/jglovier/jekyll-new) + +You can find the source code for Jekyll at [github.com/jekyll/jekyll](https://github.com/jekyll/jekyll) diff --git a/css/main.scss b/css/main.scss new file mode 100755 index 000000000..84bb3a5bf --- /dev/null +++ b/css/main.scss @@ -0,0 +1,49 @@ +--- +# Only the main Sass file needs front matter (the dashes are enough) +--- +@charset "utf-8"; + + + +// Our variables +$base-font-family: Helvetica, Arial, sans-serif; +$base-font-size: 16px; +$small-font-size: $base-font-size * 0.875; +$base-line-height: 1.5; + +$spacing-unit: 30px; + +$text-color: #111; +$background-color: #fdfdfd; +$brand-color: #2a7ae2; + +$grey-color: #828282; +$grey-color-light: lighten($grey-color, 40%); +$grey-color-dark: darken($grey-color, 25%); + +$on-palm: 600px; +$on-laptop: 800px; + + + +// Using media queries with like this: +// @include media-query($palm) { +// .wrapper { +// padding-right: $spacing-unit / 2; +// padding-left: $spacing-unit / 2; +// } +// } +@mixin media-query($device) { + @media screen and (max-width: $device) { + @content; + } +} + + + +// Import partials from `sass_dir` (defaults to `_sass`) +@import + "base", + "layout", + "syntax-highlighting" +; diff --git a/feed.xml b/feed.xml new file mode 100644 index 000000000..022378beb --- /dev/null +++ b/feed.xml @@ -0,0 +1,30 @@ +--- +layout: null +--- + + + + {{ site.title | xml_escape }} + {{ site.description | xml_escape }} + {{ site.url }}{{ site.baseurl }}/ + + {{ site.time | date_to_rfc822 }} + {{ site.time | date_to_rfc822 }} + Jekyll v{{ jekyll.version }} + {% for post in site.posts limit:10 %} + + {{ post.title | xml_escape }} + {{ post.content | xml_escape }} + {{ post.date | date_to_rfc822 }} + {{ post.url | prepend: site.baseurl | prepend: site.url }} + {{ post.url | prepend: site.baseurl | prepend: site.url }} + {% for tag in post.tags %} + {{ tag | xml_escape }} + {% endfor %} + {% for cat in post.categories %} + {{ cat | xml_escape }} + {% endfor %} + + {% endfor %} + + diff --git a/index.html b/index.html new file mode 100644 index 000000000..83d939851 --- /dev/null +++ b/index.html @@ -0,0 +1,23 @@ +--- +layout: default +--- + +
+ +

Posts

+ + + +

subscribe via RSS

+ +
From 1cdc50afd233d7d7189ffb4e034832b2a9b73716 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:02:00 -0700 Subject: [PATCH 002/386] Add the github-pages gem --- .gitignore | 1 + Gemfile | 1 + 2 files changed, 2 insertions(+) create mode 100644 Gemfile diff --git a/.gitignore b/.gitignore index c08f9add7..78bd97213 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ +.sass-cache _site \ No newline at end of file diff --git a/Gemfile b/Gemfile new file mode 100644 index 000000000..c5d8e4676 --- /dev/null +++ b/Gemfile @@ -0,0 +1 @@ +gem 'github-pages' \ No newline at end of file From 02e144ab86490ab9920da6e208f40f592254dbac Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:08:45 -0700 Subject: [PATCH 003/386] Config --- _config.yml | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/_config.yml b/_config.yml index 2f03e74d4..45daabe43 100644 --- a/_config.yml +++ b/_config.yml @@ -1,14 +1,11 @@ # Site settings -title: Your awesome title -email: your-email@domain.com +title: The Rust Programming Language Blog description: > # this means to ignore newlines until "baseurl:" - Write an awesome description for your new site here. You can edit this - line in _config.yml. It will appear in your document head meta (for - Google search results) and in your feed.xml site description. + Words from the Rust team baseurl: "" # the subpath of your site, e.g. /blog/ -url: "http://yourdomain.com" # the base hostname & protocol for your site -twitter_username: jekyllrb -github_username: jekyll +url: "http://rust-lang.org" +twitter_username: rustlang +github_username: rust-lang # Build settings markdown: kramdown From 34623cf3f9bfbab82dadaad2692d9c49f895484b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:11:08 -0700 Subject: [PATCH 004/386] Fix canonical URL --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 45daabe43..4fddd8eca 100644 --- a/_config.yml +++ b/_config.yml @@ -3,7 +3,7 @@ title: The Rust Programming Language Blog description: > # this means to ignore newlines until "baseurl:" Words from the Rust team baseurl: "" # the subpath of your site, e.g. /blog/ -url: "http://rust-lang.org" +url: "http://blog.rust-lang.org" twitter_username: rustlang github_username: rust-lang From 60e8fd449da8d8f83e6a7e07452933bd6d0677a7 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:23:58 -0700 Subject: [PATCH 005/386] Add CNAME --- CNAME | 1 + 1 file changed, 1 insertion(+) create mode 100644 CNAME diff --git a/CNAME b/CNAME new file mode 100644 index 000000000..a6d5f4379 --- /dev/null +++ b/CNAME @@ -0,0 +1 @@ +blog.rust-lang.org \ No newline at end of file From a8bf095455c3a2884ca921ce1bae2e0a61ca997e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:29:01 -0700 Subject: [PATCH 006/386] Bleh --- _config.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_config.yml b/_config.yml index 4fddd8eca..c9e370977 100644 --- a/_config.yml +++ b/_config.yml @@ -1,8 +1,8 @@ # Site settings title: The Rust Programming Language Blog -description: > # this means to ignore newlines until "baseurl:" +description: > Words from the Rust team -baseurl: "" # the subpath of your site, e.g. /blog/ +baseurl: "" url: "http://blog.rust-lang.org" twitter_username: rustlang github_username: rust-lang From 53c82eab08ec23f85dde88b0630e92be1b2149ec Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 13:40:34 -0700 Subject: [PATCH 007/386] CNAME --- CNAME | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CNAME b/CNAME index a6d5f4379..b7cc76842 100644 --- a/CNAME +++ b/CNAME @@ -1 +1 @@ -blog.rust-lang.org \ No newline at end of file +blog.rust-lang.org From 420589dd0a60cec8dccc34c003b9c16ce4bcb64c Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 8 Sep 2014 15:34:25 -0700 Subject: [PATCH 008/386] Tweak --- .gitignore | 3 ++- _posts/2014-09-08-welcome-to-jekyll.markdown | 25 ------------------- _posts/2014-09-08-welcome-to-the-rust-blog.md | 6 +++++ about.md | 11 -------- 4 files changed, 8 insertions(+), 37 deletions(-) delete mode 100644 _posts/2014-09-08-welcome-to-jekyll.markdown create mode 100644 _posts/2014-09-08-welcome-to-the-rust-blog.md delete mode 100644 about.md diff --git a/.gitignore b/.gitignore index 78bd97213..6ef5f6739 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ .sass-cache -_site \ No newline at end of file +_site +*~ \ No newline at end of file diff --git a/_posts/2014-09-08-welcome-to-jekyll.markdown b/_posts/2014-09-08-welcome-to-jekyll.markdown deleted file mode 100644 index df6a3dc0e..000000000 --- a/_posts/2014-09-08-welcome-to-jekyll.markdown +++ /dev/null @@ -1,25 +0,0 @@ ---- -layout: post -title: "Welcome to Jekyll!" -date: 2014-09-08 12:48:43 -categories: jekyll update ---- -You’ll find this post in your `_posts` directory. Go ahead and edit it and re-build the site to see your changes. You can rebuild the site in many different ways, but the most common way is to run `jekyll serve --watch`, which launches a web server and auto-regenerates your site when a file is updated. - -To add new posts, simply add a file in the `_posts` directory that follows the convention `YYYY-MM-DD-name-of-post.ext` and includes the necessary front matter. Take a look at the source for this post to get an idea about how it works. - -Jekyll also offers powerful support for code snippets: - -{% highlight ruby %} -def print_hi(name) - puts "Hi, #{name}" -end -print_hi('Tom') -#=> prints 'Hi, Tom' to STDOUT. -{% endhighlight %} - -Check out the [Jekyll docs][jekyll] for more info on how to get the most out of Jekyll. File all bugs/feature requests at [Jekyll’s GitHub repo][jekyll-gh]. If you have questions, you can ask them on [Jekyll’s dedicated Help repository][jekyll-help]. - -[jekyll]: http://jekyllrb.com -[jekyll-gh]: https://github.com/jekyll/jekyll -[jekyll-help]: https://github.com/jekyll/jekyll-help diff --git a/_posts/2014-09-08-welcome-to-the-rust-blog.md b/_posts/2014-09-08-welcome-to-the-rust-blog.md new file mode 100644 index 000000000..93ab59930 --- /dev/null +++ b/_posts/2014-09-08-welcome-to-the-rust-blog.md @@ -0,0 +1,6 @@ +--- +layout: post +title: "Welcome to the Rust blog" +--- + +There's nothing here yet. diff --git a/about.md b/about.md deleted file mode 100644 index 3ed64bb62..000000000 --- a/about.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -layout: page -title: About -permalink: /about/ ---- - -This is the base Jekyll theme. You can find out more info about customizing your Jekyll theme, as well as basic Jekyll usage documentation at [jekyllrb.com](http://jekyllrb.com/) - -You can find the source code for the Jekyll new theme at: [github.com/jglovier/jekyll-new](https://github.com/jglovier/jekyll-new) - -You can find the source code for Jekyll at [github.com/jekyll/jekyll](https://github.com/jekyll/jekyll) From 49e2d55d1934baed3d92444513103b3e9ca913da Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Sep 2014 14:19:05 -0400 Subject: [PATCH 009/386] Initial post --- _posts/2014-09-08-welcome-to-the-rust-blog.md | 6 - _posts/2014-09-15-Rust-1.0.md | 172 ++++++++++++++++++ 2 files changed, 172 insertions(+), 6 deletions(-) delete mode 100644 _posts/2014-09-08-welcome-to-the-rust-blog.md create mode 100644 _posts/2014-09-15-Rust-1.0.md diff --git a/_posts/2014-09-08-welcome-to-the-rust-blog.md b/_posts/2014-09-08-welcome-to-the-rust-blog.md deleted file mode 100644 index 93ab59930..000000000 --- a/_posts/2014-09-08-welcome-to-the-rust-blog.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -layout: post -title: "Welcome to the Rust blog" ---- - -There's nothing here yet. diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md new file mode 100644 index 000000000..a84a4b7b3 --- /dev/null +++ b/_posts/2014-09-15-Rust-1.0.md @@ -0,0 +1,172 @@ +--- +layout: post +title: "Road to Rust 1.0" +--- + +Rust 1.0 is on its way! We have nailed down a concrete list of +features and are hard at work on implementing them. We plan to ship +the 1.0 beta around the end of the year. If all goes well, this will +go on to become the 1.0 release after the beta period. After +1.0 is released, future 1.x releases will be backwards compatible, +meaning that existing code will continue to compile unmodified (modulo +compiler bugs, of course). + +Of course, a Rust 1.0 release means something more than "your code +will continue to compile". Basically, it means that we think the +design of Rust finally feels right. More specifically, it feels +*minimal*. The language itself is now focused on a simple core +concept, which we call ownership and borrowing (more on this +later). Leveraging ownership and borrowing, we are been able to build +up everything else that we have needed in libraries. This is very +exciting, because any library we can write, you can write too. This +really gives us confidence that Rust will not only achieve its +original goals but also go beyond and be used for all kinds of things +that we haven't even envisioned. + +### The road to Rust 1.0 + +Rust has gone through a long evolution. If you haven't looked at Rust +in a while, you may be surprised at what you see: over the last year, +we've been radically simplifying the design. As a prominent example, +Rust once featured several pointer types, indicated by various sigils: +these are gone, and only the reference types (`&T`, `&mut T`) +remain. We have also been able to consolidate and simplify a number of +other language features, such as closures, that once sported a wide +variety of options. (Some of these changes are still in progress.) + +The key to all these changes has been a focus on the core concepts of +*ownership and borrowing*. Initially, we introduced ownership as a +means of transferring data safely and efficiently between tasks, but +over time we have realized that the same mechanism allows us to move +all sorts of things out of the language and into libraries. The +resulting design is not only simpler to learn, but it is also much +"closer to the metal" than we ever thought possible before. All Rust +language constructs have a very direct mapping to machine operations, +and Rust has no required runtime or external dependencies. When used +in its own most minimal configuration, it is even possible to write an +[operating][k1] [systems][k4] [kernel][k2] in Rust. + +Throughout these changes, though, Rust has remained true to its goal +of providing the **safety** and **convenience** of modern programming +languages, while still offering the **efficiency** and **low-level +control** that C and C++ offer. Basically, if you want to get your +hands dirty with the bare metal machine, but you don't want to spend +hours tracking down segfaults and data races, Rust is the language for +you. + +If you're not already familiar with Rust, don't worry. Over the next +few months, we plan on issuing a regular series of blog posts +exploring the language. The first few will focus on different aspects +of ownership and how it can be used to achieve safe manual memory +management, concurrency, and more. After that, we'll turn to other +aspects of the Rust language and ecosystem. + +### What is left to do + +We've made great progress, but there is still a lot to do before the +release. Here is a list of the big-ticket changes we are currently +working on: + +- *Dynamically sized types:* This extension to the type system allows + us to uniformly handle types where the size is not known at compile + time, such as an array type. This enables us to support + user-designed smart pointers that contain arrays or + objects. Nicholas Cameron [recently landed][dst] a heroic commit + implementing the bulk of the work. +- *Unboxed closures:* Our new [closure design][cd] unifies closures + and object types. Much of the spec has been implemented. +- *Associated types:* We are moving our trait system to use + [associated types][at], which really help to cut down on the level + of generic annotations required to write advanced generic + libraries. Patrick Walton has done an initial implementation. +- *Where clauses:* We are adding a flexible new form of constraints + called [where clauses][wc]. Patrick Walton already landed support + for the basic syntax, and I have implemented the remaining + functionality on a branch that should be landing soon. +- *Multidispatch traits:* We are extending traits so that they + can [match on more than one type at a time][at], which opens up a lot of + new opportunities for more ergonomic APIs. I have + prototyped this work on a branch. +- *Destructors:* We are improving our destructor semantics to not + require zeroing of memory, which should improve compilation and + execution times. Felix Klock has implemented the requisite analysis + and is in the process of landing it. +- *Green threading:* We are removing support from green threading from + the standard library and moving it out into an external + package. This allows for a closer match between the Rust model and + the underlying operating system, which makes for more efficient + programs. Aaron Turon has [written the RFC][gt] and is getting + started on that work now. + +At the library level, we are currently engaged in a sweep over libstd +to decide what portions are stable and which are not. You can +[monitor the progress][stability] here. (Note though that many of the +'unstable' items are simply things whose name will be changed slightly +to conform to conventions or other minor tweaks.) + +### Cargo and the library ecosystem + +Earlier I wrote that Rust 1.0 is not so much an endpoint as it is a +starting point. This is very true. The goal for Rust 1.0 is to be an +flexible substrate for building efficient libraries -- but libraries +aren't any good if nobody can find them or they are difficult to install. + +Enter [Cargo, the Rust package manager](http://crates.io). Cargo has +been undergoing rapid development lately and is already quite +functional. By the time +1.0 is released, we plan to also have a central repository up and +wunning, meaning that it will be simple to create and distribute Rust +libraries (which we call "crates"). Oh, and of course Cargo and its +associated server are both written in Rust. + +### Release process + +Rust releases have been following a train schedule for a long time and +we don't plan on changing that. Once we start having stable releases, +however, we'll also build up a bit more infrastructure. Our plan is to +adopt the "channel" system used by many other projects such as +[Firefox](https://www.mozilla.org/en-US/firefox/channel/), +[Chrome](http://www.chromium.org/getting-involved/dev-channel), and +[Ember.js](http://emberjs.com/builds/). + +The idea is that there are three channels: Nighly, Beta, and +Release. The Nightly channel is what you use if you want the latest +and greatest: it includes unstable features and libraries that may +still change in backwards incompatible ways. Every six weeks, we cut a +new branch and call it Beta. This branch excludes all the unstable +bits, so you know that if you are using Beta or Release, your code +will continue to compile. At the same time, the existing Beta branch +is promoted to the Stable release. We expect that production users +will prefer to test on the Beta branch and ship with the Stable +branch. Testing on Beta ensures that we get some advanced notice if we +accidentally break anything you are relying on. + +With regard to the 1.0 release specifically, the plan is to release +the 1.0 beta and then follow this same process to transition to the +official 1.0 release. However, if we find a serious flaw in the +1.0 beta, we may defer and run an additional beta period or two. After +all, it's better to wait a bit longer than wind up committed to +something broken. + +### Looking forward + +In many ways, Rust 1.0 is not so much an endpoint as it is a starting +point. Naturally, we plan on continuing to develop Rust: we have a lot +of features we want to add, many of which are already in the pipeline. +But the work that's most exciting to me is not the work that will be +done by the Rust team. Rather, I expect that having a stable base will +allow the Rust community and ecosystem to grow much more rapidly than +it already has. I can't wait to see what comes out of it. + +[f]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+milestone%3A1.0 +[k1]: https://github.com/charliesome/rustboot +[k2]: https://github.com/jvns/puddle +[k3]: https://github.com/pczarn/rustboot +[k4]: https://github.com/ryanra/RustOS +[stability]: http://doc.rust-lang.org/std/stability.html +[dst]: https://github.com/rust-lang/rust/commit/7932b719ec2b65acfa8c3e74aad29346d47ee992 +[cd]: https://github.com/rust-lang/rfcs/blob/master/active/0044-closures.md +[wc]: https://github.com/rust-lang/rfcs/pull/135 +[at]: https://github.com/rust-lang/rfcs/pull/195 +[gt]: https://github.com/rust-lang/rfcs/pull/230 + From 76116d7548d60b1dd58f8d0c37e12539b2b01650 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Mon, 15 Sep 2014 14:36:42 -0400 Subject: [PATCH 010/386] add author --- _posts/2014-09-15-Rust-1.0.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index a84a4b7b3..421ab7d56 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -1,6 +1,7 @@ --- layout: post title: "Road to Rust 1.0" +author: Niko Matsakis --- Rust 1.0 is on its way! We have nailed down a concrete list of From 75c283e4d26e7475bc26368876d6d2576a4a7d6b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Mon, 15 Sep 2014 12:33:02 -0700 Subject: [PATCH 011/386] Release -> Stable --- _posts/2014-09-15-Rust-1.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index 421ab7d56..f799b198c 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -131,11 +131,11 @@ adopt the "channel" system used by many other projects such as [Ember.js](http://emberjs.com/builds/). The idea is that there are three channels: Nighly, Beta, and -Release. The Nightly channel is what you use if you want the latest +Stable. The Nightly channel is what you use if you want the latest and greatest: it includes unstable features and libraries that may still change in backwards incompatible ways. Every six weeks, we cut a new branch and call it Beta. This branch excludes all the unstable -bits, so you know that if you are using Beta or Release, your code +bits, so you know that if you are using Beta or Stable, your code will continue to compile. At the same time, the existing Beta branch is promoted to the Stable release. We expect that production users will prefer to test on the Beta branch and ship with the Stable From 95fa5ecc771ed18861e352298af7d0ceef6255a4 Mon Sep 17 00:00:00 2001 From: Jesse Cooke Date: Mon, 15 Sep 2014 12:43:04 -0700 Subject: [PATCH 012/386] Fix typo --- _posts/2014-09-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index f799b198c..1a7f3b2eb 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -116,7 +116,7 @@ Enter [Cargo, the Rust package manager](http://crates.io). Cargo has been undergoing rapid development lately and is already quite functional. By the time 1.0 is released, we plan to also have a central repository up and -wunning, meaning that it will be simple to create and distribute Rust +running, meaning that it will be simple to create and distribute Rust libraries (which we call "crates"). Oh, and of course Cargo and its associated server are both written in Rust. From 3f572c10f54499f61c218c8f1eb6001cd96d031d Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 15 Sep 2014 15:46:03 -0400 Subject: [PATCH 013/386] add RSS autodiscovery link --- _includes/head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/head.html b/_includes/head.html index ec8f7ca5f..762c4a07b 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -5,7 +5,7 @@ {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} - + From 174018b02bee3609c7bda220a7d5660228fe4b40 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 15 Sep 2014 16:13:17 -0400 Subject: [PATCH 014/386] fix two typos http://www.reddit.com/r/rust/comments/2ghkxz/road_to_rust_10/ckj6o6r --- _posts/2014-09-15-Rust-1.0.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index 1a7f3b2eb..66a15bf02 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -17,7 +17,7 @@ will continue to compile". Basically, it means that we think the design of Rust finally feels right. More specifically, it feels *minimal*. The language itself is now focused on a simple core concept, which we call ownership and borrowing (more on this -later). Leveraging ownership and borrowing, we are been able to build +later). Leveraging ownership and borrowing, we have been able to build up everything else that we have needed in libraries. This is very exciting, because any library we can write, you can write too. This really gives us confidence that Rust will not only achieve its @@ -92,7 +92,7 @@ working on: require zeroing of memory, which should improve compilation and execution times. Felix Klock has implemented the requisite analysis and is in the process of landing it. -- *Green threading:* We are removing support from green threading from +- *Green threading:* We are removing support for green threading from the standard library and moving it out into an external package. This allows for a closer match between the Rust model and the underlying operating system, which makes for more efficient From c0ab17003a6cfdf7c2c850b1e1d9b3be1d266c5d Mon Sep 17 00:00:00 2001 From: Chris Wong Date: Tue, 16 Sep 2014 20:16:13 +1200 Subject: [PATCH 015/386] Fix a typo --- _posts/2014-09-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index 66a15bf02..711382d00 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -130,7 +130,7 @@ adopt the "channel" system used by many other projects such as [Chrome](http://www.chromium.org/getting-involved/dev-channel), and [Ember.js](http://emberjs.com/builds/). -The idea is that there are three channels: Nighly, Beta, and +The idea is that there are three channels: Nightly, Beta, and Stable. The Nightly channel is what you use if you want the latest and greatest: it includes unstable features and libraries that may still change in backwards incompatible ways. Every six weeks, we cut a From 8876b525e05ff88264b67357b7eb874c41a338da Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 30 Oct 2014 17:49:34 -0700 Subject: [PATCH 016/386] Blog post: Stability as a Deliverable --- _posts/2014-10-30-Stability.md | 196 +++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 _posts/2014-10-30-Stability.md diff --git a/_posts/2014-10-30-Stability.md b/_posts/2014-10-30-Stability.md new file mode 100644 index 000000000..7c78d348f --- /dev/null +++ b/_posts/2014-10-30-Stability.md @@ -0,0 +1,196 @@ +--- +layout: post +title: "Stability as a Deliverable" +author: Niko Matsakis and Aaron Turon +--- + +The upcoming Rust 1.0 release means +[a lot](http://blog.rust-lang.org/2014/09/15/Rust-1.0.html), but most +fundamentally it is a commitment to stability, alongside our +long-running commitment to safety. + +Starting with 1.0, we will move to +a 6-week release cycle and a menu of release "channels". The stable +release channel will provide pain-free upgrades, and the nightly +channel will give early adopters access to unfinished features as we +work on them. + +### Committing to stability + +Since the early days of Rust, there have only been two things you +could count on: safety, and change. And sometimes not the first +one. In the process of developing Rust, we've encountered a lot of +dead ends, and so it's been essential to have the freedom to change +the language as needed. + +But Rust has matured, and core aspects of the language have been +steady for a long time. The design feels right. And there is a huge +amount of pent up interest in Rust, waiting for 1.0 to ship so that +there is a stable foundation to build on. + +It's important to be clear about what we mean by stable. We don't mean +that Rust will stop evolving. We will release new versions of Rust on +a regular, frequent basis, and we hope that people will upgrade just +as regularly. But for that to happen, those upgrades need to be +painless. + +To put it simply, our responsibility is to ensure that you never dread +upgrading Rust. If your code compiles on Rust stable 1.0, it should +compile with Rust stable 1.x with a minimum of hassle. + +### The plan + +We will use a variation of the train model, first introduced in web +browsers and now widely used to provide stability without stagnation: + +* New work lands directly in the master branch. + +* Each day, the last successful build from master becomes the new nightly release. + +* Every six weeks, a beta branch is created from the current state of + master, and the previous beta is promoted to be the new stable + release. + +In short, there are three release channels -- nightly, beta, and +stable -- with regular, frequent promotions from one channel to the +next. + +New features and new APIs will be flagged as unstable via feature gates +and +[stability attributes](http://doc.rust-lang.org/reference.html#stability), +respectively. +Unstable features and standard library APIs will only be available on +the nightly branch, and only if you explicitly "opt in" to the +instability. + +The beta and stable releases, on the other hand, will only include +features and APIs deemed *stable*, which represents a commitment to +avoid breaking code that uses those features or APIs. + +### The FAQ + +There are a lot of details involved in the above process, and we plan +to publish RFCs laying out the fine points. The rest of this post will +cover some of the most important details and potential worries about +this plan. + +#### What features will be stable for 1.0? + +We've done an analysis of the current Rust ecosystem to determine the +most used crates and the feature gates they depend on, and used this +data to guide our stabilization plan. The good news is that the vast +majority of what's currently being used will be stable by 1.0: + +* There are several features that are nearly finished already: struct + variants, default type parameters, tuple indexing, and slicing syntax. + +* There are two key features that need significant more work, but are + crucial for 1.0: unboxed closures and associated types. + +* Finally, there are some widely-used features with flaws that cannot + be addressed in the 1.0 timeframe: glob imports, macros, and syntax + extensions. This is where we have to make some tough decisions. + +After extensive discussion, we plan to release globs and macros as +stable at 1.0. For globs, we believe we can address problems in a +backwards-compatible way. For macros, we will likely provide an +alternative way to define macros (with better +[hygiene](http://en.wikipedia.org/wiki/Hygienic_macro)) at some later +date, and will incrementally improve the "macro rules" feature until +then. The 1.0 release will stabilize all current macro support, +including import/export. + +On the other hand, we *cannot* stabilize syntax extensions, which are +plugins with complete access to compiler internals. Stabilizing it +would effectively forever freeze the internals of the compiler; we +need to design a more deliberate interface between extensions and the +compiler. So syntax extensions will remain behind a feature gate for +1.0. + +Many major uses of syntax extensions could be replaced with +traditional code generation, and the Cargo tool will soon be growing +specific support for this use case. We plan to work with library +authors to help them migrate away from syntax extensions prior to +1.0. Because many syntax extensions don't fit this model, we also see +stabilizing syntax extensions as an immediate priority after the 1.0 +release. + +#### What parts of the standard library will be stable for 1.0? + +We have been steadily stabilizing the standard library, and have a +plan for nearly *all* of the modules it provides. The expectation is +that the vast majority of functionality in the standard library will +be stable for 1.0. We have also been migrating more experimental APIs +out of the standard library and into their own crates. + +#### What about stability attributes outside of the standard library? + +Library authors can continue to use stability attributes as they do +today to mark their own stability promises. These attributes are not +tied into the Rust release channels by default. That is, when you're +compiling on Rust stable, you can only use stable APIs from the +standard library, but you can opt into experimental APIs from other +libraries. The Rust release channels are about making upgrading *Rust +itself* (the compiler and standard library) painless. + +Library authors should follow [semver](http://semver.org/); we will +soon publish an RFC defining how library stability attributes and +semver interact. + +#### Why not allow opting in to instability in the stable release? + +There are three problems with allowing unstable features on the +stable release. + +First, as the web has shown numerous times, merely *advertising* +instability doesn't work. Once features are in wide use it is very +hard to change them -- and once features are available at all, it is +very hard to prevent them from being used. Mechanisms like "vendor +prefixes" on the web that were meant to support experimentation +instead led to de facto standardization. + +Second, unstable features are by definition work in progress. But the +beta/stable snapshots freeze the feature at scheduled points in time, +while library authors will want to work with the latest version of the +feature. + +Finally, we simply *cannot* deliver stability for Rust unless we +enforce it. Our promise is that, if you are using the stable release +of Rust, you will never dread upgrading to the next release. If +libraries could opt in to instability, then we could only keep this +promise if all library authors guaranteed the same thing by supporting +all three release channels simultaneously. + +It's not realistic or necessary for the entire ecosystem to flawlessly +deal with these problems. Instead, we will enforce that stable means +stable: the stable channel provides only stable features. + +#### Won't this split the ecosystem? Will everyone use nightly at 1.0? + +It doesn't split the ecosystem: it creates a subset. Programmers +working with the nightly release channel can freely use libraries that +are designed for the stable channel. There will be pressure to +stabilize important features and APIs, and so the incentives to stay +in the unstable world will shrink over time. + +We have carefully planned the 1.0 release so that the bulk of the +existing ecosystem will fit into the "stable" category, and thus +newcomers to Rust will immediately be able to use most libraries on +the stable 1.0 release. + +#### What are the stability caveats? + +We reserve the right to fix compiler bugs, patch safety holes, and +change type inference in ways that may occasionally require new type +annotations. We do not expect any of these changes to cause +headaches when upgrading Rust. + +The library API caveats will be laid out in a forthcoming RFC, but are +similarly designed to minimize upgrade pain in practice. + +#### Will Rust and its ecosystem continue their rapid development? + +Yes! Because new work can land on master at any time, the train model +doesn't slow down the pace of development or introduce artificial +delays. Rust has always evolved at a rapid pace, with lots of help +from amazing community members, and we expect this will only accelerate. From d6acbc693e4aa7d44daa8aecad3fe731e6a3deae Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 30 Oct 2014 17:55:46 -0700 Subject: [PATCH 017/386] Tweaks to stability post --- _posts/2014-10-30-Stability.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_posts/2014-10-30-Stability.md b/_posts/2014-10-30-Stability.md index 7c78d348f..19b6a225a 100644 --- a/_posts/2014-10-30-Stability.md +++ b/_posts/2014-10-30-Stability.md @@ -1,7 +1,7 @@ --- layout: post title: "Stability as a Deliverable" -author: Niko Matsakis and Aaron Turon +author: Aaron Turon and Niko Matsakis --- The upcoming Rust 1.0 release means @@ -74,7 +74,7 @@ to publish RFCs laying out the fine points. The rest of this post will cover some of the most important details and potential worries about this plan. -#### What features will be stable for 1.0? +### What features will be stable for 1.0? We've done an analysis of the current Rust ecosystem to determine the most used crates and the feature gates they depend on, and used this @@ -115,7 +115,7 @@ authors to help them migrate away from syntax extensions prior to stabilizing syntax extensions as an immediate priority after the 1.0 release. -#### What parts of the standard library will be stable for 1.0? +### What parts of the standard library will be stable for 1.0? We have been steadily stabilizing the standard library, and have a plan for nearly *all* of the modules it provides. The expectation is @@ -123,7 +123,7 @@ that the vast majority of functionality in the standard library will be stable for 1.0. We have also been migrating more experimental APIs out of the standard library and into their own crates. -#### What about stability attributes outside of the standard library? +### What about stability attributes outside of the standard library? Library authors can continue to use stability attributes as they do today to mark their own stability promises. These attributes are not @@ -137,7 +137,7 @@ Library authors should follow [semver](http://semver.org/); we will soon publish an RFC defining how library stability attributes and semver interact. -#### Why not allow opting in to instability in the stable release? +### Why not allow opting in to instability in the stable release? There are three problems with allowing unstable features on the stable release. @@ -165,7 +165,7 @@ It's not realistic or necessary for the entire ecosystem to flawlessly deal with these problems. Instead, we will enforce that stable means stable: the stable channel provides only stable features. -#### Won't this split the ecosystem? Will everyone use nightly at 1.0? +### Won't this split the ecosystem? Will everyone use nightly at 1.0? It doesn't split the ecosystem: it creates a subset. Programmers working with the nightly release channel can freely use libraries that @@ -178,7 +178,7 @@ existing ecosystem will fit into the "stable" category, and thus newcomers to Rust will immediately be able to use most libraries on the stable 1.0 release. -#### What are the stability caveats? +### What are the stability caveats? We reserve the right to fix compiler bugs, patch safety holes, and change type inference in ways that may occasionally require new type @@ -188,7 +188,7 @@ headaches when upgrading Rust. The library API caveats will be laid out in a forthcoming RFC, but are similarly designed to minimize upgrade pain in practice. -#### Will Rust and its ecosystem continue their rapid development? +### Will Rust and its ecosystem continue their rapid development? Yes! Because new work can land on master at any time, the train model doesn't slow down the pace of development or introduce artificial From a8596a4bf5ab83bf079ec6236c88e0067edbcc24 Mon Sep 17 00:00:00 2001 From: Paolo Moretti Date: Fri, 31 Oct 2014 14:40:28 +0000 Subject: [PATCH 018/386] Fix a broken link --- _posts/2014-09-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2014-09-15-Rust-1.0.md b/_posts/2014-09-15-Rust-1.0.md index 711382d00..3c8e06616 100644 --- a/_posts/2014-09-15-Rust-1.0.md +++ b/_posts/2014-09-15-Rust-1.0.md @@ -166,7 +166,7 @@ it already has. I can't wait to see what comes out of it. [k4]: https://github.com/ryanra/RustOS [stability]: http://doc.rust-lang.org/std/stability.html [dst]: https://github.com/rust-lang/rust/commit/7932b719ec2b65acfa8c3e74aad29346d47ee992 -[cd]: https://github.com/rust-lang/rfcs/blob/master/active/0044-closures.md +[cd]: https://github.com/rust-lang/rfcs/blob/master/text/0114-closures.md [wc]: https://github.com/rust-lang/rfcs/pull/135 [at]: https://github.com/rust-lang/rfcs/pull/195 [gt]: https://github.com/rust-lang/rfcs/pull/230 From 6628d471258d8d814794ce67ff4437fd38f28232 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 1 Nov 2014 10:05:38 +1100 Subject: [PATCH 019/386] Add the Rust logo to the site heading. --- _config.yml | 1 + _includes/header.html | 2 +- _sass/_layout.scss | 6 ++++++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index c9e370977..91a26e990 100644 --- a/_config.yml +++ b/_config.yml @@ -4,6 +4,7 @@ description: > Words from the Rust team baseurl: "" url: "http://blog.rust-lang.org" +logo: "http://www.rust-lang.org/logos/rust-logo-64x64-blk.png" twitter_username: rustlang github_username: rust-lang diff --git a/_includes/header.html b/_includes/header.html index cfe381f75..de7fad667 100644 --- a/_includes/header.html +++ b/_includes/header.html @@ -2,7 +2,7 @@ From 231aeb2d0e2077e9397d37db8e33d7eba1ebd6be Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 1 Nov 2014 11:09:08 +1100 Subject: [PATCH 021/386] Add the site title to the page title always. --- _includes/head.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/head.html b/_includes/head.html index 762c4a07b..f056adcec 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -3,7 +3,7 @@ - {% if page.title %}{{ page.title }}{% else %}{{ site.title }}{% endif %} + {% if page.title %}{{ page.title }} - {{ site.title }}{% else %}{{ site.title }}{% endif %} From d9d1b67c9b1681bf85f15513677bd08245b16db0 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sat, 1 Nov 2014 11:10:29 +1100 Subject: [PATCH 022/386] Add links to rust-lang.org and the guide. Hopefully people will click on these to start their Rust journey! --- _includes/footer.html | 10 +++------- _sass/_layout.scss | 8 +++++++- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/_includes/footer.html b/_includes/footer.html index be3976f7e..f2d236e92 100644 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -1,15 +1,11 @@ + +
- - -
+ + From 2a86f1db73b1c4737f9488633f158da182c07884 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 9 Jan 2015 11:19:24 -0800 Subject: [PATCH 041/386] Update analytics tracking number --- _includes/footer.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_includes/footer.html b/_includes/footer.html index 6370c4df6..9e267faee 100644 --- a/_includes/footer.html +++ b/_includes/footer.html @@ -56,7 +56,7 @@ m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m) })(window,document,'script','//www.google-analytics.com/analytics.js','ga'); - ga('create', 'UA-58390457-1', 'auto'); + ga('create', 'UA-58390457-2', 'auto'); ga('send', 'pageview'); From 382823b01273b6f3f0c675e7dd75f37f44f70e88 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Tue, 13 Jan 2015 00:31:50 +1100 Subject: [PATCH 042/386] Add some xml_escape's to twitter cards. Quotes etc. in titles or descriptions will make HTML & twitter unhappy without these. --- _includes/head.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_includes/head.html b/_includes/head.html index 2aceb33cd..8dba01e36 100644 --- a/_includes/head.html +++ b/_includes/head.html @@ -13,9 +13,9 @@ {% if page.description %} - + {% else %} - + {% endif %} From 32b3922fb2b1e21e411d53650906e4596ffabe79 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Mon, 12 Jan 2015 11:40:50 -0500 Subject: [PATCH 043/386] Add @dylanede to 1.0 alpha contributors list https://github.com/rust-lang/rust/commit/25eada15740fbe12ee2cae7fc6fe8e2c228b699d was in alpha, but Dylan wasn't credited. --- _posts/2015-01-09-Rust-1.0-alpha.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2015-01-09-Rust-1.0-alpha.md b/_posts/2015-01-09-Rust-1.0-alpha.md index ea0c496dc..425663a63 100644 --- a/_posts/2015-01-09-Rust-1.0-alpha.md +++ b/_posts/2015-01-09-Rust-1.0-alpha.md @@ -176,6 +176,7 @@ This alpha release could not have happened without the help of Rust's enthusiast * `Davis Silverman ` * `Diego Giagio ` * `Dirk Gadsden ` +* `Dylan Ede ` * `Earl St Sauver ` * `Eduard Burtescu ` * `Eduardo Bautista ` From 3cead0e4c4b7eee43c4c84a6d3a1bda665f7e561 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 13 Jan 2015 11:02:46 -0500 Subject: [PATCH 044/386] Update @rohitjoshi's email --- _posts/2015-01-09-Rust-1.0-alpha.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-01-09-Rust-1.0-alpha.md b/_posts/2015-01-09-Rust-1.0-alpha.md index 425663a63..d89b7db91 100644 --- a/_posts/2015-01-09-Rust-1.0-alpha.md +++ b/_posts/2015-01-09-Rust-1.0-alpha.md @@ -312,7 +312,7 @@ This alpha release could not have happened without the help of Rust's enthusiast * `rjz ` * `Robin Gloster ` * `Robin Stocker ` -* `Rohit Joshi ` +* `Rohit Joshi ` * `Rolf Timmermans ` * `Rolf van de Krol ` * `Roy Crihfield ` From 69c3cdf5b1b2caf79f10fa897aeb1e46f3feda7e Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 13 Feb 2015 11:16:06 -0800 Subject: [PATCH 045/386] Blog post: Rust 1.0: status report and final timeline --- _posts/2015-02-13-Final-1.0-timeline.md | 168 ++++++++++++++++++++++++ 1 file changed, 168 insertions(+) create mode 100644 _posts/2015-02-13-Final-1.0-timeline.md diff --git a/_posts/2015-02-13-Final-1.0-timeline.md b/_posts/2015-02-13-Final-1.0-timeline.md new file mode 100644 index 000000000..70cbaba12 --- /dev/null +++ b/_posts/2015-02-13-Final-1.0-timeline.md @@ -0,0 +1,168 @@ +--- +layout: post +title: "Rust 1.0: status report and final timeline" +author: The Rust Core Team +--- + +It's been five weeks since we released Rust 1.0-alpha! Before this +release cycle finishes next week, we want to give a status report and +update on the road to 1.0 final. + +**TL;DR: Rust 1.0 final will be released by May 15, 2015** + +## What is the overall timeline? + +Based on the progress in this release cycle, we are now comfortable +committing to a precise release schedule for 1.0: + +* Rust 1.0-alpha2 -- Feb 20 +* All 1.0 modules stable on nightly -- around Mar 9 +* Rust 1.0-beta -- Mar 31 +* Rust 1.0 -- May 15 + +This schedule differs from the +[previous one](http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html) +by nailing down an exact set of release cycles. It also opts for a +second alpha release and only a single beta release. + +The main reason for calling the next release alpha2 rather than beta1 +is that new path and IO APIs have only recently landed, and we would +like more time to collect feedback before marking the new path and IO +APIs stable. More details are below. + +## What's shipping in alpha2? + +We've managed to land almost all of the features +[previously expected](http://blog.rust-lang.org/2015/01/09/Rust-1.0-alpha.html) +for this cycle. + +**The big headline here is that all major API revisions are +finished**: path and IO reform have landed. At this point, all modules +shipping for 1.0 are in what we expect to be their final form, modulo +minor tweaks during the alpha2 cycle. + +Other highlights are as follows: + +* **Closures**: Rust now supports + [full capture-clause inference](https://github.com/rust-lang/rfcs/blob/master/text/0231-upvar-capture-inference.md) + and has deprecated the temporary `|:|` notation, making closures + much more ergonomic to use. + +* **Destructors**: New + [destructor rules](https://github.com/rust-lang/rfcs/pull/769) + landed, obviating the need for `#[unsafe destructor]`. + +* **Path reform**: The `path` module has been completely + [redesigned](https://github.com/rust-lang/rfcs/pull/474) to resolve + a number of semantic and ergonomic problems with the old module, and + to take advantage of DST. + +* **IO reform**: The `io` system has been + [thoroughly revised](https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md) + to improve robustness and cross-platform behavior, and to eschew + ambitious high-level abstractions over the system. While almost all + of the APIs are effected by this change, the changes move toward a + much more conservative and consistent design. + +* **Deref coercions**: A + [new coercion](https://github.com/rust-lang/rfcs/pull/241) will + follow smart pointers, so that you can pass `&Vec` where `&[T]` + is wanted, or `&Arc` where `&T` is wanted. This removes most need + for explicit slicing or the dreaded "cross-borrowing" `&*`, and + means that `&` can be thought of as a general "borrow" operator. + +* **Feature staging**: Rust now has a notion of + [named API *features*](https://github.com/rust-lang/rfcs/pull/475) + akin to language features, which is how we will manage API + stabilization going forward. These named features make it easier to + manage progress in `std`, and make it plausible to detect the + minimum version of Rust needed for a crate. + +* **For loops**: The new `IntoIterator` trait is now available and + used for `for` loops, making it possible to write `for x in &vec` + rather than `for x in vec.iter()`. + +* **Range notation**: We have + [finalized range notation](https://github.com/rust-lang/rfcs/pull/702), + introducing `..` for "full ranges", which will make APIs like + `collection.remove(..)` possible in the future. + +* **Trait system**: New coherence rules were + [finalized](http://internals.rust-lang.org/t/orphan-rules/1322), + providing both flexibility and soundness for trait implementations. + +* **Overflow semantics**: After a long debate, the final integer + overflow semantics has + [been decided](https://github.com/rust-lang/rfcs/pull/560) and is + expected to land for alpha2. This change is expected to make it much + easier to find over/underflow bugs when used in conjunction with + fuzzing, etc. + +* **Associated types**: many compiler bugs around associated types + have been fixed, making them usable at large scale. + +Some other changes have not landed at the time of writing but are +expected for alpha2: +[variance for type parameters](https://github.com/rust-lang/rfcs/pull/738), +[Send changes](https://github.com/rust-lang/rfcs/pull/458), and +[the great integer audit](https://github.com/rust-lang/rust/issues/22240). + +Complete details will be available in the release notes next week. + +## Why another alpha? + +The main reason is that we want to leave recently-landed APIs, like IO +and path, unstable for a few more weeks while we collect feedback -- +but the beta release is intended to disallow use of unstable features. + +In more detail, Rust is drawing a +[difference between alpha and beta](http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html) +connected with our +[stability system](http://blog.rust-lang.org/2014/10/30/Stability.html). +In alpha releases, it's possible to opt-in to unstable features, but +after beta, this will be possible only when using nightly builds. The +beta release will mark the point when a substantial portion of the +community can move off of nightlies. + +As mentioned above, we have landed all of the major API revisions +needed for the 1.0 release, including path and IO reform. However, +some of these revisions landed relatively late in the cycle, and as a +community we don't have enough experience with the revised APIs to +declare them stable yet. Note that the API changes are, with a +couple exceptions, very conservative: they generally move us in the +direction of existing, successful libraries. + +By producing 1.0-alpha2, we leave open a longer window for tweaks to +these APIs before declaring them stable. That window will close around +March 9. + +### Is there risk of slippage by not moving to beta now? + +It seems unlikely. Essentially all of the language and library +features needed for 1.0 have already landed, meaning that we will have +*12 weeks* of time to polish between alpha2 and 1.0 final. + +## What will happen before 1.0? + +All features that are required for shipping 1.0 have now landed. What +remains is polish, performance improvements, bugfixing, documentation +-- and gaining enough confidence in recently revised APIs to mark them +`#[stable]`. + +The alpha2 release will officially deprecate (but leave available) the +old path and IO APIs. The new APIs are scheduled to be stabilized +by March 9. **Please try out these new APIs and help uncover +problems!** + +After the March 9 deadline, it should be possible for substantial +crates to work with "stable Rust", i.e. without any use of +`#[feature]`. Between then and the beta release, we hope to work +directly with authors of crates.io packages to help move code to +stable Rust, and to uncover any gaps in stabilization. + +By beta, we hope that a substantial part of the ecosystem will be off +of nightlies and on to stable releases. Getting there will require a +community-wide push toward stabilization, which we're coordinating via +[discuss](http://users.rust-lang.org/t/using-unstable-apis-tell-us-about-it/157/26) +-- if you haven't, please drop by and tell us the key unstable APIs +you're using. From 5991d72ffe253f5950238a019f3f4d3dfcb7b993 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 13 Feb 2015 11:35:52 -0800 Subject: [PATCH 046/386] Fix typos --- _posts/2015-02-13-Final-1.0-timeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-02-13-Final-1.0-timeline.md b/_posts/2015-02-13-Final-1.0-timeline.md index 70cbaba12..b7341d99b 100644 --- a/_posts/2015-02-13-Final-1.0-timeline.md +++ b/_posts/2015-02-13-Final-1.0-timeline.md @@ -61,7 +61,7 @@ Other highlights are as follows: [thoroughly revised](https://github.com/rust-lang/rfcs/blob/master/text/0517-io-os-reform.md) to improve robustness and cross-platform behavior, and to eschew ambitious high-level abstractions over the system. While almost all - of the APIs are effected by this change, the changes move toward a + of the APIs are affected by this change, the changes move toward a much more conservative and consistent design. * **Deref coercions**: A From 404f85b1d4d3496b7b0e72b587366997c42495b8 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 13 Feb 2015 11:39:02 -0800 Subject: [PATCH 047/386] Fix redundancy --- _posts/2015-02-13-Final-1.0-timeline.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-02-13-Final-1.0-timeline.md b/_posts/2015-02-13-Final-1.0-timeline.md index b7341d99b..c7db38c59 100644 --- a/_posts/2015-02-13-Final-1.0-timeline.md +++ b/_posts/2015-02-13-Final-1.0-timeline.md @@ -27,8 +27,8 @@ second alpha release and only a single beta release. The main reason for calling the next release alpha2 rather than beta1 is that new path and IO APIs have only recently landed, and we would -like more time to collect feedback before marking the new path and IO -APIs stable. More details are below. +like more time to collect feedback before marking them stable. More +details are below. ## What's shipping in alpha2? From 1565d2c25e3adb3c182d6e85988a8d0436660675 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 20 Feb 2015 14:57:43 -0500 Subject: [PATCH 048/386] Rust 1.0-alpha2 --- _posts/2015-02-20-Rust-1.0-alpha2.md | 244 +++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 _posts/2015-02-20-Rust-1.0-alpha2.md diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md new file mode 100644 index 000000000..28bc33490 --- /dev/null +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -0,0 +1,244 @@ +--- +layout: post +title: "Announcing Rust 1.0-alpha2" +author: Steve Klabnik +description: "Rust 1.0-alpha2 has been released." +--- + +Today, we are happy to announce the release of Rust 1.0.0.alpha.2! Rust is a +systems programming language perusing the trifecta: safe, fast, and concurrent. + +In accordance with our [status report](/2015/02/13/Final-1.0-timeline.html) +last week, this is a second alpha release, rather than a first beta release. +The beta release will be six weeks from today, with the final coming six weeks +after that. + +We’ve managed to land almost all of the features previously expected for this +cycle. **The big headline here is that all major API revisions are finished**: +path and IO reform have landed. At this point, all modules shipping for 1.0 are +in what we expect to be their final form, modulo minor tweaks during the alpha2 +cycle. See the [previous post](/2015/02/13/Final-1.0-timeline.html) for more +details. + +This coming release cycle is crucial to Rust, as this will be the last cycle +that we recommend nightly builds for most users. Part of the way through the +cycle, around March 9th, we expect to have all major functionality we expect in +1.0 marked as stable; we will fill in stability gaps between then and beta on +March 31st. The beta release will fully introduce the "stable channel", which +will not allow use of unstable features but will guarantee +backwards-compatibility (after 1.0). Unstable features will only be available +in nightly. + +For more detail, please see the [Release +notes](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-alpha2-february-2015). + +Thank you to all 207 contributors for this release: + +* `Aaron Turon ` +* `Adam Roben ` +* `Adolfo Ochagavía ` +* `Ahmed Charles ` +* `Aidan Hobson Sayers ` +* `Akos Kiss ` +* `Alexander Bliskovsky ` +* `Alexander Korolkov ` +* `Alexander Light ` +* `Alex Crichton ` +* `Alexis ` +* `Alfie John ` +* `Alfie John ` +* `Andrea Canciani ` +* `Andrew Barchuk ` +* `Andrew Paseltiner ` +* `Ariel Ben-Yehuda ` +* `Ariel Ben-Yehuda ` +* `Armin Preiml ` +* `Artem ` +* `Barosl Lee ` +* `Benjamin Peterson ` +* `Ben S ` +* `Björn Steinbrink ` +* `blackbeam ` +* `bombless ` +* `Brian Anderson ` +* `Brian Leibig ` +* `caipre ` +* `Cam Jackson ` +* `Carl Lerche ` +* `Carol Nichols ` +* `Carter Hinsley ` +* `CarVac ` +* `Caspar Krieger ` +* `Chase Southwood ` +* `Chris Morgan ` +* `Chris Thorn ` +* `Chris Wong ` +* `Clifford Caoile ` +* `Corey Farwell ` +* `Corey Richardson ` +* `Daniel Griffen ` +* `Daniel Grunwald ` +* `Daniel Raloff ` +* `Daniil Smirnov ` +* `Dan Yang ` +* `David Creswick ` +* `Diggory Blake ` +* `Dominik Inführ ` +* `Duane Edwards ` +* `Duncan Regan ` +* `Dzmitry Malyshau ` +* `Earl St Sauver ` +* `Eduard Burtescu ` +* `Edward Wang ` +* `Elantsev Serj ` +* `emanueLczirai ` +* `Erick Rivas ` +* `Erick Tryzelaar ` +* `Eunji Jeong ` +* `Felix S. Klock II ` +* `Fenhl ` +* `Filip SzczepaÅ„ski ` +* `Flavio Percoco ` +* `Florian Hahn ` +* `Garrett Heel ` +* `Geoffrey Thomas ` +* `Greg Chapple ` +* `Guillaume Gomez ` +* `GuillaumeGomez ` +* `Guillaume Pinot ` +* `Henrik Schopmans ` +* `Hugo van der Wijst ` +* `Huon Wilson ` +* `Ignacio Corderi ` +* `Ingo Blechschmidt ` +* `Jake Goulding ` +* `James Miller ` +* `Jared Roesch ` +* `Jason Fager ` +* `jatinn ` +* `Jay True ` +* `Jeff Belgum ` +* `John Hodge ` +* `John KaÌŠre Alsaker ` +* `John KÃ¥re Alsaker ` +* `Jonathan Reem ` +* `JONNALAGADDA Srinivas ` +* `Jorge Aparicio ` +* `Jorge Israel Peña ` +* `Jormundir ` +* `Joseph Crail ` +* `JP Sugarbroad ` +* `Julian Orth ` +* `Junseok Lee ` +* `Kang Seonghoon ` +* `Keegan McAllister ` +* `Keegan McAllister ` +* `Ken Tossell ` +* `KernelJ ` +* `Kevin Ballard ` +* `Kevin Butler ` +* `Kevin Yap ` +* `Kim Røen ` +* `klutzy ` +* `Kostas Karachalios ` +* `kud1ing ` +* `Lai Jiangshan ` +* `Lauri Lehmijoki ` +* `Leo Testard ` +* `Liigo Zhuang ` +* `Logan Chien ` +* `Loïc Damien ` +* `Luca Bruno ` +* `Luke Francl ` +* `Luke Steensen ` +* `madmalik ` +* `Manish Goregaokar ` +* `Markus Siemens ` +* `Marvin Löbel ` +* `Matt Roche ` +* `Mátyás Mustoha ` +* `mdinger ` +* `Michael Budde ` +* `Michael Neumann ` +* `Michael Pankov ` +* `Michael Sproul ` +* `Michael Woerister ` +* `Mike English ` +* `Mikhail Zabaluev ` +* `Ms2ger ` +* `NAKASHIMA, Makoto ` +* `nathan dotz ` +* `Nathaniel Theis ` +* `Nathan Stoddard ` +* `Nelson Chen ` +* `Nick Cameron ` +* `Nick Howell ` +* `Nick Sarten ` +* `Niko Matsakis ` +* `NODA, Kai ` +* `Oliver 'ker' Schneider ` +* `Oliver Schneider ` +* `Orpheus Lummis ` +* `P1start ` +* `Pascal Hertleif ` +* `Paul Collier ` +* `Paul Crowley ` +* `Peter Atashian ` +* `Peter Schuller ` +* `Pierre Baillet ` +* `Piotr Czarnecki ` +* `posixphreak ` +* `Potpourri ` +* `Pyfisch ` +* `Raul Gutierrez S ` +* `Renato Alves ` +* `Renato Zannon ` +* `Richo Healey ` +* `Robin Stocker ` +* `Rohit Joshi ` +* `Ryan Levick ` +* `Sean Collins ` +* `Sean Gillespie ` +* `Sean Patrick Santos ` +* `Sean T Allen ` +* `Sebastian Gesemann ` +* `Sebastian Rasmussen ` +* `Sébastien Marie ` +* `Seo Sanghyeon ` +* `Seth Faxon ` +* `Simonas Kazlauskas ` +* `Stepan Koltsov ` +* `Steve Klabnik ` +* `Steven Allen ` +* `Steven Crockett ` +* `Steven Fackler ` +* `Strahinja Val Markovic ` +* `Thiago Carvalho ` +* `Tim Brooks ` +* `Tim Cuthbertson ` +* `Tim Dumol ` +* `Tim Parenti ` +* `Tobias Bucher ` +* `Toby Scrace ` +* `Tom Chittenden ` +* `Tom Jakubowski ` +* `Toni Cárdenas ` +* `Travis Watkins ` +* `Tristan Storch ` +* `Tshepang Lekhonkhobe ` +* `Tyler Thrailkill ` +* `Ulrik Sverdrup ` +* `Vadim Chugunov ` +* `Vadim Petrochenkov ` +* `Valerii Hiora ` +* `Victory ` +* `visualfc ` +* `Vojtech Kral ` +* `Volker Mische ` +* `Wangshan Lu ` +* `we ` +* `Willson Mock ` +* `Will ` +* `wonyong kim ` +* `York Xiang ` + From a8c58a5000966f4a83363d37a822154bf630fb8e Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 20 Feb 2015 12:05:57 -0800 Subject: [PATCH 049/386] Fix names --- _posts/2015-02-20-Rust-1.0-alpha2.md | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index 28bc33490..a7fdf4496 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -36,7 +36,7 @@ Thank you to all 207 contributors for this release: * `Aaron Turon ` * `Adam Roben ` -* `Adolfo Ochagavía ` +* `Adolfo Ochagavía ` * `Ahmed Charles ` * `Aidan Hobson Sayers ` * `Akos Kiss ` @@ -57,7 +57,7 @@ Thank you to all 207 contributors for this release: * `Barosl Lee ` * `Benjamin Peterson ` * `Ben S ` -* `Björn Steinbrink ` +* `Björn Steinbrink ` * `blackbeam ` * `bombless ` * `Brian Anderson ` @@ -83,7 +83,7 @@ Thank you to all 207 contributors for this release: * `Dan Yang ` * `David Creswick ` * `Diggory Blake ` -* `Dominik Inführ ` +* `Dominik Inführ ` * `Duane Edwards ` * `Duncan Regan ` * `Dzmitry Malyshau ` @@ -97,7 +97,7 @@ Thank you to all 207 contributors for this release: * `Eunji Jeong ` * `Felix S. Klock II ` * `Fenhl ` -* `Filip SzczepaÅ„ski ` +* `Filip Szczepański ` * `Flavio Percoco ` * `Florian Hahn ` * `Garrett Heel ` @@ -119,12 +119,12 @@ Thank you to all 207 contributors for this release: * `Jay True ` * `Jeff Belgum ` * `John Hodge ` -* `John KaÌŠre Alsaker ` -* `John KÃ¥re Alsaker ` +* `John Kåre Alsaker ` +* `John Kåre Alsaker ` * `Jonathan Reem ` * `JONNALAGADDA Srinivas ` * `Jorge Aparicio ` -* `Jorge Israel Peña ` +* `Jorge Israel Peña ` * `Jormundir ` * `Joseph Crail ` * `JP Sugarbroad ` @@ -138,7 +138,7 @@ Thank you to all 207 contributors for this release: * `Kevin Ballard ` * `Kevin Butler ` * `Kevin Yap ` -* `Kim Røen ` +* `Kim Røen ` * `klutzy ` * `Kostas Karachalios ` * `kud1ing ` @@ -147,16 +147,16 @@ Thank you to all 207 contributors for this release: * `Leo Testard ` * `Liigo Zhuang ` * `Logan Chien ` -* `Loïc Damien ` +* `Loïc Damien ` * `Luca Bruno ` * `Luke Francl ` * `Luke Steensen ` * `madmalik ` * `Manish Goregaokar ` * `Markus Siemens ` -* `Marvin Löbel ` +* `Marvin Löbel ` * `Matt Roche ` -* `Mátyás Mustoha ` +* `Mátyás Mustoha ` * `mdinger ` * `Michael Budde ` * `Michael Neumann ` @@ -203,7 +203,7 @@ Thank you to all 207 contributors for this release: * `Sean T Allen ` * `Sebastian Gesemann ` * `Sebastian Rasmussen ` -* `Sébastien Marie ` +* `Sébastien Marie ` * `Seo Sanghyeon ` * `Seth Faxon ` * `Simonas Kazlauskas ` @@ -222,7 +222,7 @@ Thank you to all 207 contributors for this release: * `Toby Scrace ` * `Tom Chittenden ` * `Tom Jakubowski ` -* `Toni Cárdenas ` +* `Toni Cárdenas ` * `Travis Watkins ` * `Tristan Storch ` * `Tshepang Lekhonkhobe ` @@ -241,4 +241,3 @@ Thank you to all 207 contributors for this release: * `Will ` * `wonyong kim ` * `York Xiang ` - From 27f2520e58373cea6e4b3ac7130c9d45b35a63da Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 20 Feb 2015 15:13:34 -0500 Subject: [PATCH 050/386] versioning is hard, consistent versioning is harder --- _posts/2015-02-20-Rust-1.0-alpha2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index a7fdf4496..51b5be9d2 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -1,8 +1,8 @@ --- layout: post -title: "Announcing Rust 1.0-alpha2" +title: "Announcing Rust 1.0.0.alpha.2" author: Steve Klabnik -description: "Rust 1.0-alpha2 has been released." +description: "Rust 1.0.0.alpha.2 has been released." --- Today, we are happy to announce the release of Rust 1.0.0.alpha.2! Rust is a From c755e9d2dc1f222f62213050af62b7857cbce1af Mon Sep 17 00:00:00 2001 From: elliottcf Date: Fri, 20 Feb 2015 14:55:47 -0600 Subject: [PATCH 051/386] Fixed word choice Replaced perusing or pursuing --- _posts/2015-02-20-Rust-1.0-alpha2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index 51b5be9d2..32b7f59e0 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -6,7 +6,7 @@ description: "Rust 1.0.0.alpha.2 has been released." --- Today, we are happy to announce the release of Rust 1.0.0.alpha.2! Rust is a -systems programming language perusing the trifecta: safe, fast, and concurrent. +systems programming language pursuing the trifecta: safe, fast, and concurrent. In accordance with our [status report](/2015/02/13/Final-1.0-timeline.html) last week, this is a second alpha release, rather than a first beta release. From 84fa18acd40a50c6b0a39790e9de2a7e491e925a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 20 Feb 2015 16:08:40 -0500 Subject: [PATCH 052/386] Fix typo Thanks parley https://news.ycombinator.com/item?id=9082849 --- _posts/2015-02-20-Rust-1.0-alpha2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index 51b5be9d2..32b7f59e0 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -6,7 +6,7 @@ description: "Rust 1.0.0.alpha.2 has been released." --- Today, we are happy to announce the release of Rust 1.0.0.alpha.2! Rust is a -systems programming language perusing the trifecta: safe, fast, and concurrent. +systems programming language pursuing the trifecta: safe, fast, and concurrent. In accordance with our [status report](/2015/02/13/Final-1.0-timeline.html) last week, this is a second alpha release, rather than a first beta release. From e2cb108333687274fc1bd2f2d8f781d8bda0f8d9 Mon Sep 17 00:00:00 2001 From: sjef Date: Fri, 20 Feb 2015 23:20:17 +0100 Subject: [PATCH 053/386] Remove duplicate name in contributor list --- _posts/2015-02-20-Rust-1.0-alpha2.md | 1 - 1 file changed, 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index 32b7f59e0..eff3c945a 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -119,7 +119,6 @@ Thank you to all 207 contributors for this release: * `Jay True ` * `Jeff Belgum ` * `John Hodge ` -* `John Kåre Alsaker ` * `John Kåre Alsaker ` * `Jonathan Reem ` * `JONNALAGADDA Srinivas ` From e0e6b44ff98707715e9a1699868cc27f68c7e588 Mon Sep 17 00:00:00 2001 From: Ingve Date: Fri, 20 Feb 2015 23:48:56 +0100 Subject: [PATCH 054/386] Remove duplicate name in contributor list Surely it is the same person. --- _posts/2015-02-20-Rust-1.0-alpha2.md | 1 - 1 file changed, 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index eff3c945a..b4b748969 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -104,7 +104,6 @@ Thank you to all 207 contributors for this release: * `Geoffrey Thomas ` * `Greg Chapple ` * `Guillaume Gomez ` -* `GuillaumeGomez ` * `Guillaume Pinot ` * `Henrik Schopmans ` * `Hugo van der Wijst ` From 6f8a6b3a40c93a785f52be422be31585c19b7842 Mon Sep 17 00:00:00 2001 From: Ingve Date: Fri, 20 Feb 2015 23:52:49 +0100 Subject: [PATCH 055/386] Correct the amount of contributors --- _posts/2015-02-20-Rust-1.0-alpha2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index b4b748969..75f727b3e 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -32,7 +32,7 @@ in nightly. For more detail, please see the [Release notes](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-alpha2-february-2015). -Thank you to all 207 contributors for this release: +Thank you to all 205 contributors for this release: * `Aaron Turon ` * `Adam Roben ` From 6a5ee2c775957f81439512e60480e8ddf5ae7ff7 Mon Sep 17 00:00:00 2001 From: York Xiang Date: Sat, 21 Feb 2015 06:56:15 +0800 Subject: [PATCH 056/386] Remove duplicate contributor --- _posts/2015-01-09-Rust-1.0-alpha.md | 1 - _posts/2015-02-20-Rust-1.0-alpha2.md | 3 +-- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/_posts/2015-01-09-Rust-1.0-alpha.md b/_posts/2015-01-09-Rust-1.0-alpha.md index d89b7db91..657fec2d1 100644 --- a/_posts/2015-01-09-Rust-1.0-alpha.md +++ b/_posts/2015-01-09-Rust-1.0-alpha.md @@ -146,7 +146,6 @@ This alpha release could not have happened without the help of Rust's enthusiast * `Bheesham Persaud ` * `Björn Steinbrink ` * `bluss ` -* `bombless ` * `Boris Egorov ` * `bors ` * `Brandon Sanderson ` diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index eff3c945a..1e8d217f8 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -32,7 +32,7 @@ in nightly. For more detail, please see the [Release notes](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-alpha2-february-2015). -Thank you to all 207 contributors for this release: +Thank you to all 205 contributors for this release: * `Aaron Turon ` * `Adam Roben ` @@ -59,7 +59,6 @@ Thank you to all 207 contributors for this release: * `Ben S ` * `Björn Steinbrink ` * `blackbeam ` -* `bombless ` * `Brian Anderson ` * `Brian Leibig ` * `caipre ` From 0548c8e6459493e45dcc189e5d7458a0b0c10fa5 Mon Sep 17 00:00:00 2001 From: York Xiang Date: Sat, 21 Feb 2015 09:10:22 +0800 Subject: [PATCH 057/386] Correct amount of contributors --- _posts/2015-02-20-Rust-1.0-alpha2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-02-20-Rust-1.0-alpha2.md b/_posts/2015-02-20-Rust-1.0-alpha2.md index 3c578919b..b0e957681 100644 --- a/_posts/2015-02-20-Rust-1.0-alpha2.md +++ b/_posts/2015-02-20-Rust-1.0-alpha2.md @@ -32,7 +32,7 @@ in nightly. For more detail, please see the [Release notes](https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-alpha2-february-2015). -Thank you to all 205 contributors for this release: +Thank you to all 204 contributors for this release: * `Aaron Turon ` * `Adam Roben ` From 2adc5f6dcbb77b1115f15e164e4a6f146e69bdec Mon Sep 17 00:00:00 2001 From: Matt Brubeck Date: Tue, 31 Mar 2015 15:44:37 -0700 Subject: [PATCH 058/386] Correct the date for 1.0-beta --- _posts/2015-02-13-Final-1.0-timeline.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_posts/2015-02-13-Final-1.0-timeline.md b/_posts/2015-02-13-Final-1.0-timeline.md index c7db38c59..2eb65f074 100644 --- a/_posts/2015-02-13-Final-1.0-timeline.md +++ b/_posts/2015-02-13-Final-1.0-timeline.md @@ -17,7 +17,7 @@ committing to a precise release schedule for 1.0: * Rust 1.0-alpha2 -- Feb 20 * All 1.0 modules stable on nightly -- around Mar 9 -* Rust 1.0-beta -- Mar 31 +* Rust 1.0-beta -- Apr 3 * Rust 1.0 -- May 15 This schedule differs from the @@ -30,6 +30,10 @@ is that new path and IO APIs have only recently landed, and we would like more time to collect feedback before marking them stable. More details are below. +**Update:** An earlier version of this post listed Mar 31 as the 1.0-beta +release date, due to a miscalculation. The correct date is Apr 3, exactly six +weeks after alpha2 and six weeks before 1.0. + ## What's shipping in alpha2? We've managed to land almost all of the features From 3691d4cb325f7c1f29073bf1d309a8e817a0c904 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 3 Apr 2015 13:02:48 -0400 Subject: [PATCH 059/386] Add beta post --- _posts/2015-04-03-Rust-1.0-beta.md | 244 +++++++++++++++++++++++++++++ 1 file changed, 244 insertions(+) create mode 100644 _posts/2015-04-03-Rust-1.0-beta.md diff --git a/_posts/2015-04-03-Rust-1.0-beta.md b/_posts/2015-04-03-Rust-1.0-beta.md new file mode 100644 index 000000000..f8ed6c51b --- /dev/null +++ b/_posts/2015-04-03-Rust-1.0-beta.md @@ -0,0 +1,244 @@ +--- +layout: post +title: "Announcing Rust 1.0 Beta" +author: The Rust Core Team +--- + +Today we are excited to announce the [release of Rust 1.0 beta][ru]! +The beta release marks a very significant "state transition" in the +move towards 1.0. In particular, with the beta release, **all +libraries and language features that are planned to be stable for 1.0 +have been marked as stable**. As such, the beta release represents an +accurate preview of what Rust 1.0 will include. + +The Beta release also marks a turning point in our +[approach to stability][as]. During the alpha cycle, the use of +unstable APIs and language features was permitted, but triggered a +warning. As of the Beta release, the use of unstable APIs will become +an error (unless you are using Nightly builds or building from +source). + +The Rust ecosystem continues to grow. The +[crates.io](https://crates.io/) repository just passed 1 million +downloads and has over 1,700 crates available. Many of the top crates +in [crates.io](https://crates.io/) can now be built using only stable +Rust, and efforts to port the remainder are underway. Therefore, we +are now recommending that new users start with the Beta release, +rather than the Nightly builds, and the [rustup script][ru] will be +modified to install Beta by default. (However, it is easy to switch to +the Nightly build if some of your dependencies aren't updated yet. See +the [install page][ru] for details.) + +[ru]: http://www.rust-lang.org/install.html +[as]: http://blog.rust-lang.org/2014/10/30/Stability.html + +### What happens during the beta cycle? + +**The final Rust 1.0 release is scheduled for May 15th -- exactly six +weeks from now.** In the interim, we expect to put most of our effort +into fixing bugs, improving documentation and error messages, and +otherwise improving the end-user experience. We don't plan on making +functional changes to stable content, though naturally we may make +minor corrections or additions to the library APIs if shortcomings or +problems are uncovered (but the bar for such changes is relatively +high). + +While we don't expect to add any new features (or major new APIs) for +the 1.0 release, that doesn't mean we're going to stop working on them +altogether. In fact, quite the opposite! Per [the train model][tm], +the plan is to continue development on new features on the master +branch, in parallel with the beta. And of course, we'll be issuing the +beta for 1.1 release at the same time as we issue the final 1.0 +release, so you shouldn't have to wait long to start putting that work +to use. + +To help ensure that we don't accidentally introduce breakage as we add +new features, we've also been working on an exciting new CI +infrastructure to allow us to monitor which packages are building with +the Nightly builds and detect regressions across the entire Rust +ecosystem, not just our own test base. This infrastructure is still in +the development phase, but you can see a [sample report][sr] here. + +[tm]: http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html +[sr]: https://gist.github.com/brson/a30a77836fbec057cbee + +### A community achievement + +As always, this Rust release is the achievement of the fantastic Rust +community at large. Thanks to everyone who has participated in the RFC +process, and a particular thank you to the 172 contributors for this +release: + +- `Aaron Turon ` +- `Aaron Weiss ` +- `Adam Jacob ` +- `Adenilson Cavalcanti ` +- `Adolfo Ochagavía ` +- `Ahmed Charles ` +- `Alan Cutter ` +- `Alex Crichton ` +- `Alexander Bliskovsky ` +- `Alexander Campbell ` +- `Alexander Chernyakhovsky ` +- `Alexis ` +- `Alexis Beingessner ` +- `Amol Mundayoor ` +- `Anders Kaseorg ` +- `Andrew Hobden ` +- `Andrew Paseltiner ` +- `Angus Lees ` +- `Barosl Lee ` +- `Björn Steinbrink ` +- `Brian Anderson ` +- `Brian Brooks ` +- `Brian Leibig ` +- `Camille Roussel ` +- `Camille TJHOA ` +- `Carol Nichols ` +- `Caspar Krieger ` +- `Ches Martin ` +- `Chloe <5paceToast@users.noreply.github.com>` +- `Chris Wong ` +- `Cody P Schafer ` +- `Corey Farwell ` +- `Corey Richardson ` +- `Dabo Ross ` +- `Dan Burkert ` +- `Dan Connolly ` +- `Dan W. <1danwade@gmail.com>` +- `Daniel Lobato García ` +- `Darin Morrison ` +- `Darrell Hamilton ` +- `Dave Huseby ` +- `David Creswick ` +- `David King ` +- `David Mally ` +- `Denis Defreyne ` +- `Drew Crawford ` +- `Dzmitry Malyshau ` +- `Eduard Bopp ` +- `Eduard Burtescu ` +- `Eduardo Bautista ` +- `Edward Wang ` +- `Emeliov Dmitrii ` +- `Eric Platon ` +- `Erick Tryzelaar ` +- `Eunji Jeong ` +- `Falco Hirschenberger ` +- `Felix S. Klock II ` +- `Fenhl ` +- `Flavio Percoco ` +- `Florian Hahn ` +- `Florian Hartwig ` +- `Florian Zeitz ` +- `FuGangqiang ` +- `Gary M. Josack ` +- `Germano Gabbianelli ` +- `GlacJAY ` +- `Gleb Kozyrev ` +- `Guillaume Gomez ` +- `GuillaumeGomez ` +- `Huachao Huang ` +- `Huon Wilson ` +- `Ivan Petkov ` +- `Ivan Radanov Ivanov ` +- `JP-Ellis ` +- `Jake Goulding ` +- `Jakub Bukaj ` +- `James Miller ` +- `Jessy Diamond Exum ` +- `Jihyun Yu ` +- `Johannes Oertel ` +- `John Hodge ` +- `John Zhang ` +- `Jonathan Reem ` +- `Jordan Woehr ` +- `Jorge Aparicio ` +- `Joseph Crail ` +- `Julian Orth ` +- `Julian Viereck ` +- `Junseok Lee ` +- `Kang Seonghoon ` +- `Keegan McAllister ` +- `Kevin Ballard ` +- `Kevin Butler ` +- `Kevin Yap ` +- `Lai Jiangshan ` +- `Leonids Maslovs ` +- `Liam Monahan ` +- `Liigo Zhuang ` +- `Manish Goregaokar ` +- `Markus Siemens ` +- `Markus Unterwaditzer ` +- `Marvin Löbel ` +- `Matt Brubeck ` +- `Matt Cox ` +- `Michael Woerister ` +- `Michał Krasnoborski ` +- `Mihnea Dobrescu-Balaur ` +- `Mikhail Zabaluev ` +- `Ms2ger ` +- `Murarth ` +- `Nicholas ` +- `Nicholas Bishop ` +- `Nicholas Mazzuca ` +- `Nick Cameron ` +- `Niko Matsakis ` +- `Oliver Schneider ` +- `Or Neeman ` +- `Pascal Hertleif ` +- `Patrick Walton ` +- `Paul ADENOT ` +- `Paul Osborne ` +- `Peter Elmers ` +- `Phil Dawes ` +- `Philip Munksgaard ` +- `Piotr Czarnecki ` +- `Pyry Kontio ` +- `Raphael Nestler ` +- `Ricardo Martins ` +- `Richard Diamond ` +- `Richo Healey ` +- `Ruud van Asseldonk ` +- `Ryan Prichard ` +- `Sae-bom Kim ` +- `Scott Olson ` +- `Sean McArthur ` +- `Seo Sanghyeon ` +- `Simonas Kazlauskas ` +- `Simonas Kazlauskas ` +- `Stepan Koltsov ` +- `Stepan Koltsov ` +- `Steve Klabnik ` +- `Steven Crockett ` +- `Steven Fackler ` +- `Sébastien Marie ` +- `Tamir Duberstein ` +- `Tero Hänninen ` +- `Tiago Nobrega ` +- `Tobias Bucher ` +- `Tom Jakubowski ` +- `Trent Nadeau ` +- `Tshepang Lekhonkhobe ` +- `Ulrik Sverdrup ` +- `Vadim Chugunov ` +- `Vadim Petrochenkov ` +- `Valerii Hiora ` +- `Vladimir Pouzanov ` +- `Vojtech Kral ` +- `Wangshan Lu ` +- `Wesley Wiser ` +- `York Xiang ` +- `awlnx ` +- `bcoopers ` +- `bombless ` +- `defuz ` +- `inrustwetrust ` +- `kgv ` +- `kjpgit ` +- `lummax ` +- `mdinger ` +- `nwin ` +- `ray glover ` +- `Łukasz Niemier ` + From 873dfc1f9e2899e58f05ce5601867eb0187b2fca Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 3 Apr 2015 14:06:30 -0400 Subject: [PATCH 060/386] uhhh release notes --- _posts/2015-04-03-Rust-1.0-beta.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_posts/2015-04-03-Rust-1.0-beta.md b/_posts/2015-04-03-Rust-1.0-beta.md index f8ed6c51b..a313e8694 100644 --- a/_posts/2015-04-03-Rust-1.0-beta.md +++ b/_posts/2015-04-03-Rust-1.0-beta.md @@ -11,6 +11,10 @@ libraries and language features that are planned to be stable for 1.0 have been marked as stable**. As such, the beta release represents an accurate preview of what Rust 1.0 will include. +To see what has changed since 1.0-alpha2, please see the [release notes][rn]. + +[rn]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-beta-april-2015 + The Beta release also marks a turning point in our [approach to stability][as]. During the alpha cycle, the use of unstable APIs and language features was permitted, but triggered a From ff8b73c5a3d29e9100b97a45691de2fcc1b93efe Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 3 Apr 2015 14:48:17 -0400 Subject: [PATCH 061/386] remove incorrect link Fixes #36 --- _posts/2014-10-30-Stability.md | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/_posts/2014-10-30-Stability.md b/_posts/2014-10-30-Stability.md index 250b76fc2..cfc43a9ce 100644 --- a/_posts/2014-10-30-Stability.md +++ b/_posts/2014-10-30-Stability.md @@ -57,12 +57,9 @@ stable -- with regular, frequent promotions from one channel to the next. New features and new APIs will be flagged as unstable via feature gates -and -[stability attributes](http://doc.rust-lang.org/reference.html#stability), -respectively. -Unstable features and standard library APIs will only be available on -the nightly branch, and only if you explicitly "opt in" to the -instability. +and stability attributes respectively. Unstable features and standard +library APIs will only be available on the nightly branch, and only if you +explicitly "opt in" to the instability. The beta and stable releases, on the other hand, will only include features and APIs deemed *stable*, which represents a commitment to From c030c4c8d80d3ca8e2e6720c2fc3c75b1fc73399 Mon Sep 17 00:00:00 2001 From: Huon Wilson Date: Sun, 5 Apr 2015 23:34:51 +1000 Subject: [PATCH 062/386] Sort contributor list unicode-aware & folding case. --- _posts/2015-04-03-Rust-1.0-beta.md | 33 +++++++++++++++--------------- 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/_posts/2015-04-03-Rust-1.0-beta.md b/_posts/2015-04-03-Rust-1.0-beta.md index a313e8694..867681c87 100644 --- a/_posts/2015-04-03-Rust-1.0-beta.md +++ b/_posts/2015-04-03-Rust-1.0-beta.md @@ -91,8 +91,11 @@ release: - `Andrew Hobden ` - `Andrew Paseltiner ` - `Angus Lees ` +- `awlnx ` - `Barosl Lee ` +- `bcoopers ` - `Björn Steinbrink ` +- `bombless ` - `Brian Anderson ` - `Brian Brooks ` - `Brian Leibig ` @@ -117,6 +120,7 @@ release: - `David Creswick ` - `David King ` - `David Mally ` +- `defuz ` - `Denis Defreyne ` - `Drew Crawford ` - `Dzmitry Malyshau ` @@ -144,9 +148,9 @@ release: - `GuillaumeGomez ` - `Huachao Huang ` - `Huon Wilson ` +- `inrustwetrust ` - `Ivan Petkov ` - `Ivan Radanov Ivanov ` -- `JP-Ellis ` - `Jake Goulding ` - `Jakub Bukaj ` - `James Miller ` @@ -159,6 +163,7 @@ release: - `Jordan Woehr ` - `Jorge Aparicio ` - `Joseph Crail ` +- `JP-Ellis ` - `Julian Orth ` - `Julian Viereck ` - `Junseok Lee ` @@ -167,27 +172,33 @@ release: - `Kevin Ballard ` - `Kevin Butler ` - `Kevin Yap ` +- `kgv ` +- `kjpgit ` - `Lai Jiangshan ` - `Leonids Maslovs ` - `Liam Monahan ` - `Liigo Zhuang ` +- `Łukasz Niemier ` +- `lummax ` - `Manish Goregaokar ` - `Markus Siemens ` - `Markus Unterwaditzer ` - `Marvin Löbel ` - `Matt Brubeck ` - `Matt Cox ` +- `mdinger ` - `Michael Woerister ` - `Michał Krasnoborski ` - `Mihnea Dobrescu-Balaur ` - `Mikhail Zabaluev ` - `Ms2ger ` - `Murarth ` -- `Nicholas ` - `Nicholas Bishop ` - `Nicholas Mazzuca ` +- `Nicholas ` - `Nick Cameron ` - `Niko Matsakis ` +- `nwin ` - `Oliver Schneider ` - `Or Neeman ` - `Pascal Hertleif ` @@ -200,6 +211,7 @@ release: - `Piotr Czarnecki ` - `Pyry Kontio ` - `Raphael Nestler ` +- `ray glover ` - `Ricardo Martins ` - `Richard Diamond ` - `Richo Healey ` @@ -208,15 +220,15 @@ release: - `Sae-bom Kim ` - `Scott Olson ` - `Sean McArthur ` +- `Sébastien Marie ` - `Seo Sanghyeon ` -- `Simonas Kazlauskas ` - `Simonas Kazlauskas ` +- `Simonas Kazlauskas ` - `Stepan Koltsov ` - `Stepan Koltsov ` - `Steve Klabnik ` - `Steven Crockett ` - `Steven Fackler ` -- `Sébastien Marie ` - `Tamir Duberstein ` - `Tero Hänninen ` - `Tiago Nobrega ` @@ -233,16 +245,3 @@ release: - `Wangshan Lu ` - `Wesley Wiser ` - `York Xiang ` -- `awlnx ` -- `bcoopers ` -- `bombless ` -- `defuz ` -- `inrustwetrust ` -- `kgv ` -- `kjpgit ` -- `lummax ` -- `mdinger ` -- `nwin ` -- `ray glover ` -- `Łukasz Niemier ` - From 411e7a690dd79defe40691e175c09d1043f3dbd9 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 9 Apr 2015 17:06:59 -0700 Subject: [PATCH 063/386] Add blog post: Fearless Concurrency with Rust --- _posts/2015-04-10-Fearless-Concurrency.md | 591 ++++++++++++++++++++++ 1 file changed, 591 insertions(+) create mode 100644 _posts/2015-04-10-Fearless-Concurrency.md diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md new file mode 100644 index 000000000..cb8e5ef51 --- /dev/null +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -0,0 +1,591 @@ +--- +layout: post +title: "Fearless Concurrency with Rust" +author: Aaron Turon +--- + +Rust solves an apparent contradiction: safe systems programming. Its +secret weapon is *ownership*, a concept ubiquitous in systems +programming that Rust's compiler statically checks for you. The +result: you can program without a garbage collector *and* without fear +of segfaults, because Rust will catch your mistakes. + +**The same tools that make Rust safe also help tackle concurrency +head-on.** After all, use-after-free bugs and synchronization bugs +both happen when code accesses data it shouldn't -- and as we'll +see, ownership is all about access control. + +Here's a taste of concurrency in Rust: + +* A [channel][mpsc] transfers ownership of the messages sent along it, + so you can send a pointer from one thread to another without fear of + the threads later racing for access through that pointer. + +* A [lock][mutex] knows what data it protects, and Rust guarantees + that the data can only be accessed when the lock is held. + +* Every data type knows whether it can safely be [sent][send] between + or [accessed][sync] by multiple threads, and Rust enforces this safe + usage; there are no data races. + +* You can even [share stack frames][scoped] between threads, and Rust + will statically ensure that the frames remain active while other + threads are using them. + +None of the above benefits require any special knowledge to be built +in to the compiler. Locks, channels, semaphores, atomic operations and +so on are all *libraries* that take advantage of Rust's existing +features to provide the static checking underlying these strong +guarantees. + +The goal of this post is to give you some idea of how that's done. + +### Background: ownership + +> We'll start with an overview of Rust's ownership and borrowing +systems. If you're already familiar with these, you can skip the two +"background" sections and jump straight into concurrency. If you want +a deeper introduction, I can't recommend +[Yehuda Katz's post](http://blog.skylight.io/rust-means-never-having-to-close-a-socket/) +highly enough. And +[the Rust book](http://doc.rust-lang.org/book/ownership.html) has all +the details. + +In Rust, every value has an "owning scope," and passing or returning a +value means transferring ownership ("moving" it) to a new +scope. Values that are still owned when a scope ends are automatically +destroyed at that point. + +Let's look at some simple examples. Suppose we create a vector and +push some elements onto it: + +```rust +fn make_vec() { + let mut vec = Vec::new(); // owned by make_vec's scope + vec.push(0); + vec.push(1); + // scope ends, `vec` is destroyed +} +``` + +The scope that creates a value also initially owns it. In this case, +the `make_vec` function's body (the part within `{` and `}`) is the +owning scope for `vec`. The owner can do anything it likes with `vec`, +including mutating it by pushing. At the end of the scope, `vec` is +still owned, so it is automatically deallocated. + +Things get more interesting if the vector is returned or passed around: + +```rust +fn make_vec() -> Vec { + let mut vec = Vec::new(); + vec.push(0); + vec.push(1); + vec // transfer ownership to the caller +} + +fn print_vec(vec: Vec) { + // the `vec` parameter is part of this scope, so it's owned by `print_vec` + + for i in vec.iter() { + println!("{}", i) + } + + // now, `vec` is deallocated +} + +fn use_vec() { + let vec = make_vec(); // take ownership of the vector + print_vec(vec); // pass ownership to `print_vec` +} +``` + +Now, just before `make_vec`'s scope ends, `vec` is moved out by +returning it; it is not destroyed. A caller like `use_vec` then +receives ownership of the vector. + +On the other hand, the `print_vec` function takes a `vec` parameter, +and ownership of the vector is transferred *to* it by its +caller. Since `print_vec` does not transfer the ownership any further, +at the end of its scope the vector is destroyed. + +Once ownership has been given away, a value can no longer be used. For +example, consider this variant of `use_vec`: + +```rust +fn use_vec() { + let vec = make_vec(); // take ownership of the vector + print_vec(vec); // pass ownership to `print_vec` + + for i in vec.iter() { // continue using `vec` + println!("{}", i * 2) + } +} +``` + +If you feed this version to the compiler, you'll get an error: + +``` +error: use of moved value: `vec` + +for i in vec.iter() { + ^~~ +``` + +The compiler is saying `vec` is no longer available; ownership has +been transferred elsewhere. And that's very good, because the vector +has already been deallocated at this point! + +Disaster averted. + +### Background: borrowing + +The story so far isn't very satisfying, because it's not our intent +for `print_vec` to destroy the vector it was given. What we really +want is to grant `print_vec` *temporary* access to the vector, and +then continue using the vector afterwards. + +This is where *borrowing* comes in. If you have access to a value in +Rust, you can lend out that access to the functions you call. **Rust +will check that these leases do not outlive the object being +borrowed**. + +To borrow a value, you make a *reference* to it (a kind of pointer), +using the `&` operator: + +```rust +fn print_vec(vec: &Vec) { + // the `vec` parameter is borrowed for this scope + + for i in vec.iter() { + println!("{}", i) + } + + // now, the borrow ends +} + +fn use_vec() { + let vec = make_vec(); // take ownership of the vector + print_vec(&vec); // lend access to `print_vec` + for i in vec.iter() { // continue using `vec` + println!("{}", i * 2) + } + // vec is destroyed here +} +``` + +Now `print_vec` takes a reference to a vector, and `use_vec` lends out +the vector by writing `&vec`. Since borrows are temporary, `use_vec` +retains ownership of the vector; it can continue using it after the +call to `print_vec` returns (and its lease on `vec` has expired). + +Each reference is valid for a limited scope, which the compiler will +automatically determine. References come in two flavors: + +* Immutable references `&T`, which allow aliasing but not mutation. + There can be multiple `&T` references to the same value + simultaneously, but the value cannot be mutated while those + references are active. + +* Mutable references `&mut T`, which allow mutation but not aliasing. + If there is an `&mut T` reference to a value, there can be no other + active references at that time, but the value can be mutated. + +Rust checks these rules at compile time; borrowing has no runtime +overhead. + +Why have two kinds of references? Consider a function like: + +```rust +fn push_all(from: &Vec, to: &mut Vec) { + for i in from.iter() { + to.push(*i); + } +} +``` + +This function iterates over each element of one vector, pushing it +onto another. The iterator keeps a pointer into the vector at the +current and final positions, stepping one toward the other. + +Suppose we called this function with the same vector for both arguments: + +```rust +push_all(&vec, &mut vec) +``` + +This would spell disaster! As we're pushing elements onto the vector, +it will occasionally need to resize, allocating a new hunk of memory +and copying its elements over to it. The iterator would be left with a +dangling pointer into the old memory, leading to memory unsafety (with +attendant segfaults and worse). + +Fortunately, Rust ensures that **whenever a mutable borrow is active, +no other borrows of the object are active**, producing the message: + +``` +error: cannot borrow `vec` as mutable because it is also borrowed as immutable +push_all(&vec, &mut vec); + ^~~ +``` + +Disaster averted. + +### Message passing + +Now that we've covered the basic ownership story in Rust, let's see +what it means for concurrency. + +Concurrent programming comes in many styles, but a particularly simple +one is message passing, where threads or actors communicate by sending +each other messages. Proponents of the style emphasize the way that +it ties together sharing and communication: + +> Do not communicate by sharing memory; instead, share memory by +> communicating. +> +> --[Effective Go](http://golang.org/doc/effective_go.html) + +**Rust's ownership makes it easy to turn that advice into a +compiler-checked rule**. Consider the following channel API +([channels in Rust's standard library][mpsc] are a bit different): + +```rust +fn send(chan: &Channel, t: T); +fn recv(chan: &Channel) -> T; +``` + +Channels are generic over the type of data they transmit (the `` part of the API). The `Send` part means that `T` must be +considered safe to send between threads; we'll come back to that later +in the post, but for now it's enough to know that `Vec` is +`Send`. + +As always in Rust, passing in a `T` to the `send` function means +transferring ownership of it. This fact has profound consequences: it +means that code like the following will generate a compiler error. + +```rust +// Suppose chan: Channel> + +let mut vec = Vec::new(); +// do some computation +send(&chan, vec); +print_vec(&vec); +``` + +Here, the thread creates a vector, sends it to another thread, and +then continues using it. The thread receiving the vector could mutate +it as this thread continues running, so the call to `print_vec` could +lead to race condition or, for that matter, a use-after-free bug. + +Instead, the Rust compiler will produce an error message on the call +to `print_vec`: + +``` +Error: use of moved value `vec` +``` + +Disaster averted. + +### Locks + +Another way to deal with concurrency is by having threads communicate +through passive, shared state. + +Shared-state concurrency has a bad rap. It's easy to forget to acquire +a lock, or otherwise mutate the wrong data at the wrong time, with +disastrous results -- so easy that many eschew the style altogether. + +Rust's take is that: + +1. Shared-state concurrency is a fundamental programming style, needed +for systems code, for maximal performance, and for implementing +other styles of concurrency. + +2. The problem is really about *accidentally* shared state. + +Rust aims to give you the tools to conquer shared-state concurrency +directly. + +In Rust, threads are "isolated" from each other automatically, due to +ownership. Writes can only happen when the thread has mutable access, +either by owning the data, or by having a mutable borrow of it. Either +way, **the thread is guaranteed to be the only one with access at the +time**. To see how this plays out, let's look at locks. + +Remember that mutable borrows cannot occur simultaneously with other +borrows. Locks provide the same guarantee ("mutual exclusion") through +synchronization at runtime. That leads to a locking API that hooks +directly into Rust's ownership system. + +Here is a simplified version (the [standard library's][mutex] +is more ergonomic): + +```rust +// create a new mutes +fn mutex(t: T) -> Mutex; + +// acquire the lock +fn lock(mutex: &Mutex) -> MutexGuard; + +// access the data protected by the lock +fn access(guard: &mut MutexGuard) -> &mut T; +``` + +This lock API is unusual in several respects. + +First, the `Mutex` type is generic over a type `T` of **the data +protected by the lock**. When you create a `Mutex`, you transfer +ownership of that data *into* the mutex, immediately giving up access +to it. (Locks are unlocked when they are first created.) + +Later, you can `lock` to block the thread until the lock is +acquired. This function, too, is unusual in providing a return value, +`MutexGuard`. The `MutexGuard` automatically releases the lock when +it is destroyed; there is no separate `unlock` function. + +The only way to access the lock is through the `access` function, +which turns a mutable borrow of the guard into a mutable borrow of the +data (with a shorter lease): + +```rust +fn use_lock(mutex: &Mutex>) { + // acquire the lock, taking ownership of a guard; + // the lock is held for the rest of the scope + let mut guard = lock(mutex); + + // access the data by mutably borrowing the guard + let vec = access(&mut guard); + + // vec has type `&mut Vec` + vec.push(3); + + // lock automatically released here, when `guard` is destroyed +} +``` + +There are two key ingredients here: + +* The mutable reference returned by `access` cannot outlive the + `MutexGuard` it is borrowing from. + +* The lock is only released when the `MutexGuard` is destroyed. + +The result is that **Rust will not let you access lock-protected data +except when holding the lock**. Any attempt to do otherwise will +generate a compiler error. For example, consider the following buggy +"refactoring": + +```rust +fn use_lock(mutex: &Mutex>) { + let vec = { + // acquire the lock + let mut guard = lock(mutex); + + // attempt to return a borrow of the data + access(&mut guard) + + // guard is destroyed here, releasing the lock + }; + + // attempt to access the data outside of the lock. + vec.push(3); +} +``` + +Rust will generate an error pinpointing the problem: + +``` +error: `guard` does not live long enough +access(&mut guard) + ^~~~~ +``` + +Disaster averted. + +### Thread safety and `Send` + +It's typical to distinguish some data types as "thread safe" and +others not. Thread safe data structures use enough internal +synchronization to be safely used by multiple threads concurrently. + +For example, Rust ships with two kinds of "smart pointers" for +reference counting: + +* `Rc` provides reference counting via normal reads/writes. It is + not thread safe. + +* `Arc` provides reference counting via *atomic* operations. It is + thread safe. + +The hardware atomic operations used by `Arc` are generally more +expensive than the vanilla operations used by `Rc`, so it's +advantageous to use `Rc` rather than `Arc` wherever possible. On the +other hand, it's critical that an `Rc` never migrate from one +thread to another, because that could lead to race conditions that +corrupt the count. + +Usually, the only recourse is careful documentation; most languages +make no *actual* distinction between thread-safe and thread-unsafe +types. + +In Rust, the world is divided into two kinds of data types: those that +are [`Send`][send], meaning they can be safely moved from one thread to +another, and those that are `!Send`, meaning that it may not be safe +to do so. If all of a type's components are `Send`, so is that type -- +which covers most types. Certain base types are not inherently +thread-safe, though, so it's also possible to explicitly mark a type +like `Arc` as `Send`, saying to the compiler: "Trust me; I've verified +the necessary synchronization here." + +Naturally, `Arc` is `Send`, and `Rc` is not. + +We already saw that the `Channel` and `Mutex` APIs work only with +`Send` data. since they are the point at which data crosses thread +boundaries, they are also the point of enforcement for `Send`. + +Putting this all together, Rust programmers can reap the benefits of +`Rc` and other thread-unsafe types with confidence, knowing that if +they ever do accidentally try to send one to another thread, the Rust +compiler will say: + +``` +`Rc>` cannot be sent between threads safely +``` + +Disaster averted. + +### Sharing the stack: `scoped` + +So far, all the patterns we've seen involve creating data structures +on the heap that get shared between threads. But what if we wanted to +start some threads that make use of data living in our stack frame? +That could be dangerous: + +```rust +fn parent() { + let mut vec = Vec::new(); + // fill the vector + thread::spawn(|| { + print_vec(&vec) + }) +} +``` + +The child thread take a reference to `vec`, which in turn resides in +the stack frame of `parent`. When `parent` exists, the stack frame is +popped, but the child thread is none the wiser. Oops! + +To rule out such memory unsafety, Rust's basic thread spawning API +looks a bit like this: + +```rust +fn spawn(f: F) where F: 'static, ... +``` + +The `'static` constraint is a way of saying, roughly, that no borrowed +data is permitted in the closure. It means that a function like +`parent` above will generate an error: + +``` +error: `vec` does not live long enough +``` + +essentially catching the possibility of `parent`'s stack frame +popping. Disaster averted. + +But there is another way to guarantee safety: ensure that the parent +stack frame stays put until the child thread is done. This is the +pattern of *fork-join* programming, often used for divide-and-conquer +parallel algorithms. Rust supports it by providing a +["scoped"][scoped] variant of thread spawning: + +```rust +fn scoped<'a, F>(f: F) -> JoinGuard<'a> where F: 'a, ... +``` + +There are two key differences from the `spawn` API above: + +* The use a parameter `'a`, rather than `'static`. This parameter + represents a scope that encompasses all the borrows within the + closure, `f`. + +* The return value, a `JoinGuard`. As its name suggests, `JoinGuard` + ensures that the parent thread joins (waits on) its child, by + performing an implicit join in its destructor (if one hasn't happened + explicitly already). + +Including `'a` in `JoinGuard` ensures that the `JoinGuard` **cannot +escape the scope of any data borrowed by the closure**. In other +words, Rust guarantees that the parent thread waits for the child to +finish before popping any stack frames the child might have access to. + +Thus by adjusting our previous example, we can fix the bug and satisfy +the compiler: + +```rust +fn parent() { + let mut vec = Vec::new(); + // fill the vector + let guard = thread::scoped(|| { + print_vec(&vec) + }) + // guard destroyed here, implicitly joining +} +``` + +So in Rust, you can freely borrow stack data into child threads, +confident that the compiler will check for sufficient synchronization. + +### Data races + +At this point, we've seen enough to venture a strong statement about +Rust's approach to concurrency: the compiler prevents all *data races*. + +> A data race is any unsynchronized, concurrent access to data +> involving a write. + +Synchronization here includes things as low-level as atomic +instructions. Essentially, this is a way of saying that you cannot +accidentally "share state" between threads; all (mutating) access to +state has to be mediated by *some* form of synchronization. + +Data races are just one (very important) kind of race condition, but +by preventing them, Rust often helps you prevent other, more subtle +races as well. For example, it's often important that updates to +different locations appear to take place *atomically*: other threads +see either all of the updates, or none of them. In Rust, having `&mut` +access to the relevant locations at the same time **guarantees +atomicity of updates to them**, since no other thread could possibly +have concurrent read access. + +In short, ownership and borrowing give rise to *two* key value +propositions for Rust: + +* Memory safety without garbage collection. +* Concurrency without data races. + +### The future + +When Rust first began, it baked channels directly into the language, +taking a very opinionated stance on concurrency. + +In today's Rust, concurrency is *entirely* a library affair; +everything described in this post, including `Send`, is defined in the +standard library, and could be defined in an external library instead. + +And that's very exciting, because it means that Rust's concurrency +story can endlessly evolve, growing to encompass new paradigms and +catch new classes of bugs. Libraries like [syncbox][syncbox] and +[simple_parallel][simple_parallel] are taking some of the first steps, +and we expect to invest heavily in this space in the next few +months. Stay tuned! + +[mpsc]: http://static.rust-lang.org/doc/master/std/sync/mpsc/index.html +[mutex]: http://static.rust-lang.org/doc/master/std/sync/struct.Mutex.html +[send]: http://static.rust-lang.org/doc/master/std/marker/trait.Send.html +[sync]: http://static.rust-lang.org/doc/master/std/marker/trait.Sync.html +[scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html +[syncbox]: https://github.com/carllerche/syncbox +[simple_parallel]: https://github.com/huonw/simple_parallel From 6eaf25bb0a5a4a0b1fdbae90ef4e7ccaa4c6d6c0 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 01:13:50 -0700 Subject: [PATCH 064/386] Revisions to intro --- _posts/2015-04-10-Fearless-Concurrency.md | 56 +++++++++++++++-------- 1 file changed, 37 insertions(+), 19 deletions(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index cb8e5ef51..243390f6e 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -4,39 +4,57 @@ title: "Fearless Concurrency with Rust" author: Aaron Turon --- -Rust solves an apparent contradiction: safe systems programming. Its -secret weapon is *ownership*, a concept ubiquitous in systems -programming that Rust's compiler statically checks for you. The -result: you can program without a garbage collector *and* without fear -of segfaults, because Rust will catch your mistakes. +The Rust project was initiated to solve two thorny problems: -**The same tools that make Rust safe also help tackle concurrency -head-on.** After all, use-after-free bugs and synchronization bugs -both happen when code accesses data it shouldn't -- and as we'll -see, ownership is all about access control. +* How do you do safe systems programming? +* How do you do make concurrency painless? + +Initially these problems seemed orthogonal, but to our amazement, they +turned out to really be the same: **the same tools that make Rust safe +also help you tackle concurrency head-on**. + +Memory safety bugs and concurrency bugs often come down to code +accessing data when it shouldn't. Rust's secret weapon is *ownership*, +a discipline for access control that systems programmers try to +follow, but that Rust's compiler checks statically for you. + +For memory safety, this means you can program without a garbage +collector *and* without fear of segfaults, because Rust will catch +your mistakes. + +For concurrency, this means you can choose from a wide variety of +paradigms (message passing, shared state, lock-free, purely +functional), and Rust's ownership will help you avoid the associated +pitfalls. Here's a taste of concurrency in Rust: * A [channel][mpsc] transfers ownership of the messages sent along it, so you can send a pointer from one thread to another without fear of - the threads later racing for access through that pointer. + the threads later racing for access through that pointer. **Channels + enforce thread isolation.** * A [lock][mutex] knows what data it protects, and Rust guarantees - that the data can only be accessed when the lock is held. + that the data can only be accessed when the lock is held. State is + never accidentally shared. **"Lock data, not code" is enforced in + Rust.** * Every data type knows whether it can safely be [sent][send] between or [accessed][sync] by multiple threads, and Rust enforces this safe - usage; there are no data races. + usage; there are no data races, even for lock-free data structures. + **Thread safety isn't just documentation; it's law.** * You can even [share stack frames][scoped] between threads, and Rust will statically ensure that the frames remain active while other - threads are using them. - -None of the above benefits require any special knowledge to be built -in to the compiler. Locks, channels, semaphores, atomic operations and -so on are all *libraries* that take advantage of Rust's existing -features to provide the static checking underlying these strong -guarantees. + threads are using them. **Even the most daring forms of sharing are + guaranteed safe in Rust**. + +All of these benefits come out of Rust's ownership model, and in fact +locks, channels, lock-fee data structures and so on are defined in +libraries, not the core language. That means that Rust's approach to +concurrency is *open ended*: new libraries can embrace new paradigms and +catch new bugs, just by adding APIs that take advantage of Rust's +general ownership features. The goal of this post is to give you some idea of how that's done. From 17c678d7fcfe11d41d1836fe4665a15c158f76d9 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 01:53:26 -0700 Subject: [PATCH 065/386] Add description field --- _posts/2015-04-10-Fearless-Concurrency.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index 243390f6e..c1670f30d 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -2,6 +2,7 @@ layout: post title: "Fearless Concurrency with Rust" author: Aaron Turon +description: "Rust's vision for concurrency" --- The Rust project was initiated to solve two thorny problems: From 64fbfd921d66d5b9525a7ebb09ae6fcd6d77a59c Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 09:20:49 -0700 Subject: [PATCH 066/386] Final round of revisions --- _posts/2015-04-10-Fearless-Concurrency.md | 79 ++++++++++++----------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index c1670f30d..e81c1f4d2 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -10,9 +10,9 @@ The Rust project was initiated to solve two thorny problems: * How do you do safe systems programming? * How do you do make concurrency painless? -Initially these problems seemed orthogonal, but to our amazement, they -turned out to really be the same: **the same tools that make Rust safe -also help you tackle concurrency head-on**. +Initially these problems seemed orthogonal, but to our amazement, the +solution turned out to be identical: **the same tools that make Rust +safe also help you tackle concurrency head-on**. Memory safety bugs and concurrency bugs often come down to code accessing data when it shouldn't. Rust's secret weapon is *ownership*, @@ -25,15 +25,14 @@ your mistakes. For concurrency, this means you can choose from a wide variety of paradigms (message passing, shared state, lock-free, purely -functional), and Rust's ownership will help you avoid the associated -pitfalls. +functional), and Rust will help you avoid common pitfalls. Here's a taste of concurrency in Rust: * A [channel][mpsc] transfers ownership of the messages sent along it, so you can send a pointer from one thread to another without fear of - the threads later racing for access through that pointer. **Channels - enforce thread isolation.** + the threads later racing for access through that pointer. **Rust's + channels enforce thread isolation.** * A [lock][mutex] knows what data it protects, and Rust guarantees that the data can only be accessed when the lock is held. State is @@ -53,9 +52,9 @@ Here's a taste of concurrency in Rust: All of these benefits come out of Rust's ownership model, and in fact locks, channels, lock-fee data structures and so on are defined in libraries, not the core language. That means that Rust's approach to -concurrency is *open ended*: new libraries can embrace new paradigms and -catch new bugs, just by adding APIs that take advantage of Rust's -general ownership features. +concurrency is *open ended*: new libraries can embrace new paradigms +and catch new bugs, just by adding APIs that use Rust's ownership +features. The goal of this post is to give you some idea of how that's done. @@ -88,10 +87,10 @@ fn make_vec() { ``` The scope that creates a value also initially owns it. In this case, -the `make_vec` function's body (the part within `{` and `}`) is the -owning scope for `vec`. The owner can do anything it likes with `vec`, -including mutating it by pushing. At the end of the scope, `vec` is -still owned, so it is automatically deallocated. +the body of `make_vec` is the owning scope for `vec`. The owner can do +anything it likes with `vec`, including mutating it by pushing. At the +end of the scope, `vec` is still owned, so it is automatically +deallocated. Things get more interesting if the vector is returned or passed around: @@ -159,7 +158,7 @@ Disaster averted. ### Background: borrowing -The story so far isn't very satisfying, because it's not our intent +The story so far isn't totally satisfying, because it's not our intent for `print_vec` to destroy the vector it was given. What we really want is to grant `print_vec` *temporary* access to the vector, and then continue using the vector afterwards. @@ -201,12 +200,12 @@ call to `print_vec` returns (and its lease on `vec` has expired). Each reference is valid for a limited scope, which the compiler will automatically determine. References come in two flavors: -* Immutable references `&T`, which allow aliasing but not mutation. +* Immutable references `&T`, which allow sharing but not mutation. There can be multiple `&T` references to the same value simultaneously, but the value cannot be mutated while those references are active. -* Mutable references `&mut T`, which allow mutation but not aliasing. +* Mutable references `&mut T`, which allow mutation but not sharing. If there is an `&mut T` reference to a value, there can be no other active references at that time, but the value can be mutated. @@ -227,7 +226,7 @@ This function iterates over each element of one vector, pushing it onto another. The iterator keeps a pointer into the vector at the current and final positions, stepping one toward the other. -Suppose we called this function with the same vector for both arguments: +What if we called this function with the same vector for both arguments? ```rust push_all(&vec, &mut vec) @@ -237,7 +236,7 @@ This would spell disaster! As we're pushing elements onto the vector, it will occasionally need to resize, allocating a new hunk of memory and copying its elements over to it. The iterator would be left with a dangling pointer into the old memory, leading to memory unsafety (with -attendant segfaults and worse). +attendant segfaults or worse). Fortunately, Rust ensures that **whenever a mutable borrow is active, no other borrows of the object are active**, producing the message: @@ -318,14 +317,14 @@ disastrous results -- so easy that many eschew the style altogether. Rust's take is that: -1. Shared-state concurrency is a fundamental programming style, needed -for systems code, for maximal performance, and for implementing -other styles of concurrency. +1. Shared-state concurrency is nevertheless a fundamental programming +style, needed for systems code, for maximal performance, and for +implementing other styles of concurrency. 2. The problem is really about *accidentally* shared state. Rust aims to give you the tools to conquer shared-state concurrency -directly. +directly, whether you're using locking or lock-free techniques. In Rust, threads are "isolated" from each other automatically, due to ownership. Writes can only happen when the thread has mutable access, @@ -391,10 +390,10 @@ There are two key ingredients here: * The lock is only released when the `MutexGuard` is destroyed. -The result is that **Rust will not let you access lock-protected data -except when holding the lock**. Any attempt to do otherwise will -generate a compiler error. For example, consider the following buggy -"refactoring": +The result is that **Rust enforces locking discipline: it will not let +you access lock-protected data except when holding the lock**. Any +attempt to do otherwise will generate a compiler error. For example, +consider the following buggy "refactoring": ```rust fn use_lock(mutex: &Mutex>) { @@ -438,15 +437,14 @@ reference counting: * `Arc` provides reference counting via *atomic* operations. It is thread safe. -The hardware atomic operations used by `Arc` are generally more -expensive than the vanilla operations used by `Rc`, so it's -advantageous to use `Rc` rather than `Arc` wherever possible. On the -other hand, it's critical that an `Rc` never migrate from one -thread to another, because that could lead to race conditions that -corrupt the count. +The hardware atomic operations used by `Arc` are more expensive than +the vanilla operations used by `Rc`, so it's advantageous to use `Rc` +rather than `Arc`. On the other hand, it's critical that an `Rc` +never migrate from one thread to another, because that could lead to +race conditions that corrupt the count. Usually, the only recourse is careful documentation; most languages -make no *actual* distinction between thread-safe and thread-unsafe +make no *semantic* distinction between thread-safe and thread-unsafe types. In Rust, the world is divided into two kinds of data types: those that @@ -465,7 +463,7 @@ We already saw that the `Channel` and `Mutex` APIs work only with boundaries, they are also the point of enforcement for `Send`. Putting this all together, Rust programmers can reap the benefits of -`Rc` and other thread-unsafe types with confidence, knowing that if +`Rc` and other thread-*unsafe* types with confidence, knowing that if they ever do accidentally try to send one to another thread, the Rust compiler will say: @@ -560,7 +558,7 @@ confident that the compiler will check for sufficient synchronization. ### Data races At this point, we've seen enough to venture a strong statement about -Rust's approach to concurrency: the compiler prevents all *data races*. +Rust's approach to concurrency: **the compiler prevents all *data races*.** > A data race is any unsynchronized, concurrent access to data > involving a write. @@ -579,8 +577,13 @@ access to the relevant locations at the same time **guarantees atomicity of updates to them**, since no other thread could possibly have concurrent read access. -In short, ownership and borrowing give rise to *two* key value -propositions for Rust: +It's worth pausing for a moment to think about this guarantee in the +broader landscape of languages. Many languages provide memory safety +through garbage collection. But garbage collection doesn't give you +any help in preventing data races. + +Rust instead uses ownership and borrowing to provide its two key value +propositions: * Memory safety without garbage collection. * Concurrency without data races. From b35727916027e99fc2f601ff7e9fc09fd8ef14a3 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 09:31:15 -0700 Subject: [PATCH 067/386] Fix code fence problem --- _posts/2015-04-10-Fearless-Concurrency.md | 84 +++++++++++------------ 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index e81c1f4d2..0808053e7 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -77,14 +77,14 @@ destroyed at that point. Let's look at some simple examples. Suppose we create a vector and push some elements onto it: -```rust +~~~~rust fn make_vec() { let mut vec = Vec::new(); // owned by make_vec's scope vec.push(0); vec.push(1); // scope ends, `vec` is destroyed } -``` +~~~~ The scope that creates a value also initially owns it. In this case, the body of `make_vec` is the owning scope for `vec`. The owner can do @@ -94,7 +94,7 @@ deallocated. Things get more interesting if the vector is returned or passed around: -```rust +~~~~rust fn make_vec() -> Vec { let mut vec = Vec::new(); vec.push(0); @@ -116,7 +116,7 @@ fn use_vec() { let vec = make_vec(); // take ownership of the vector print_vec(vec); // pass ownership to `print_vec` } -``` +~~~~ Now, just before `make_vec`'s scope ends, `vec` is moved out by returning it; it is not destroyed. A caller like `use_vec` then @@ -130,7 +130,7 @@ at the end of its scope the vector is destroyed. Once ownership has been given away, a value can no longer be used. For example, consider this variant of `use_vec`: -```rust +~~~~rust fn use_vec() { let vec = make_vec(); // take ownership of the vector print_vec(vec); // pass ownership to `print_vec` @@ -139,16 +139,16 @@ fn use_vec() { println!("{}", i * 2) } } -``` +~~~~ If you feed this version to the compiler, you'll get an error: -``` +~~~~ error: use of moved value: `vec` for i in vec.iter() { ^~~ -``` +~~~~ The compiler is saying `vec` is no longer available; ownership has been transferred elsewhere. And that's very good, because the vector @@ -171,7 +171,7 @@ borrowed**. To borrow a value, you make a *reference* to it (a kind of pointer), using the `&` operator: -```rust +~~~~rust fn print_vec(vec: &Vec) { // the `vec` parameter is borrowed for this scope @@ -190,7 +190,7 @@ fn use_vec() { } // vec is destroyed here } -``` +~~~~ Now `print_vec` takes a reference to a vector, and `use_vec` lends out the vector by writing `&vec`. Since borrows are temporary, `use_vec` @@ -214,13 +214,13 @@ overhead. Why have two kinds of references? Consider a function like: -```rust +~~~~rust fn push_all(from: &Vec, to: &mut Vec) { for i in from.iter() { to.push(*i); } } -``` +~~~~ This function iterates over each element of one vector, pushing it onto another. The iterator keeps a pointer into the vector at the @@ -228,9 +228,9 @@ current and final positions, stepping one toward the other. What if we called this function with the same vector for both arguments? -```rust +~~~~rust push_all(&vec, &mut vec) -``` +~~~~ This would spell disaster! As we're pushing elements onto the vector, it will occasionally need to resize, allocating a new hunk of memory @@ -241,11 +241,11 @@ attendant segfaults or worse). Fortunately, Rust ensures that **whenever a mutable borrow is active, no other borrows of the object are active**, producing the message: -``` +~~~~ error: cannot borrow `vec` as mutable because it is also borrowed as immutable push_all(&vec, &mut vec); ^~~ -``` +~~~~ Disaster averted. @@ -268,10 +268,10 @@ it ties together sharing and communication: compiler-checked rule**. Consider the following channel API ([channels in Rust's standard library][mpsc] are a bit different): -```rust +~~~~rust fn send(chan: &Channel, t: T); fn recv(chan: &Channel) -> T; -``` +~~~~ Channels are generic over the type of data they transmit (the `` part of the API). The `Send` part means that `T` must be @@ -283,14 +283,14 @@ As always in Rust, passing in a `T` to the `send` function means transferring ownership of it. This fact has profound consequences: it means that code like the following will generate a compiler error. -```rust +~~~~rust // Suppose chan: Channel> let mut vec = Vec::new(); // do some computation send(&chan, vec); print_vec(&vec); -``` +~~~~ Here, the thread creates a vector, sends it to another thread, and then continues using it. The thread receiving the vector could mutate @@ -300,9 +300,9 @@ lead to race condition or, for that matter, a use-after-free bug. Instead, the Rust compiler will produce an error message on the call to `print_vec`: -``` +~~~~ Error: use of moved value `vec` -``` +~~~~ Disaster averted. @@ -340,7 +340,7 @@ directly into Rust's ownership system. Here is a simplified version (the [standard library's][mutex] is more ergonomic): -```rust +~~~~rust // create a new mutes fn mutex(t: T) -> Mutex; @@ -349,7 +349,7 @@ fn lock(mutex: &Mutex) -> MutexGuard; // access the data protected by the lock fn access(guard: &mut MutexGuard) -> &mut T; -``` +~~~~ This lock API is unusual in several respects. @@ -367,7 +367,7 @@ The only way to access the lock is through the `access` function, which turns a mutable borrow of the guard into a mutable borrow of the data (with a shorter lease): -```rust +~~~~rust fn use_lock(mutex: &Mutex>) { // acquire the lock, taking ownership of a guard; // the lock is held for the rest of the scope @@ -381,7 +381,7 @@ fn use_lock(mutex: &Mutex>) { // lock automatically released here, when `guard` is destroyed } -``` +~~~~ There are two key ingredients here: @@ -395,7 +395,7 @@ you access lock-protected data except when holding the lock**. Any attempt to do otherwise will generate a compiler error. For example, consider the following buggy "refactoring": -```rust +~~~~rust fn use_lock(mutex: &Mutex>) { let vec = { // acquire the lock @@ -410,15 +410,15 @@ fn use_lock(mutex: &Mutex>) { // attempt to access the data outside of the lock. vec.push(3); } -``` +~~~~ Rust will generate an error pinpointing the problem: -``` +~~~~ error: `guard` does not live long enough access(&mut guard) ^~~~~ -``` +~~~~ Disaster averted. @@ -467,9 +467,9 @@ Putting this all together, Rust programmers can reap the benefits of they ever do accidentally try to send one to another thread, the Rust compiler will say: -``` +~~~~ `Rc>` cannot be sent between threads safely -``` +~~~~ Disaster averted. @@ -480,7 +480,7 @@ on the heap that get shared between threads. But what if we wanted to start some threads that make use of data living in our stack frame? That could be dangerous: -```rust +~~~~rust fn parent() { let mut vec = Vec::new(); // fill the vector @@ -488,7 +488,7 @@ fn parent() { print_vec(&vec) }) } -``` +~~~~ The child thread take a reference to `vec`, which in turn resides in the stack frame of `parent`. When `parent` exists, the stack frame is @@ -497,17 +497,17 @@ popped, but the child thread is none the wiser. Oops! To rule out such memory unsafety, Rust's basic thread spawning API looks a bit like this: -```rust +~~~~rust fn spawn(f: F) where F: 'static, ... -``` +~~~~ The `'static` constraint is a way of saying, roughly, that no borrowed data is permitted in the closure. It means that a function like `parent` above will generate an error: -``` +~~~~ error: `vec` does not live long enough -``` +~~~~ essentially catching the possibility of `parent`'s stack frame popping. Disaster averted. @@ -518,9 +518,9 @@ pattern of *fork-join* programming, often used for divide-and-conquer parallel algorithms. Rust supports it by providing a ["scoped"][scoped] variant of thread spawning: -```rust +~~~~rust fn scoped<'a, F>(f: F) -> JoinGuard<'a> where F: 'a, ... -``` +~~~~ There are two key differences from the `spawn` API above: @@ -541,7 +541,7 @@ finish before popping any stack frames the child might have access to. Thus by adjusting our previous example, we can fix the bug and satisfy the compiler: -```rust +~~~~rust fn parent() { let mut vec = Vec::new(); // fill the vector @@ -550,7 +550,7 @@ fn parent() { }) // guard destroyed here, implicitly joining } -``` +~~~~ So in Rust, you can freely borrow stack data into child threads, confident that the compiler will check for sufficient synchronization. From 467f5d7d2543d55031b599ee00e55b36192e3c26 Mon Sep 17 00:00:00 2001 From: Ricardo Mendes Date: Fri, 10 Apr 2015 17:40:44 +0100 Subject: [PATCH 068/386] Typo in code comment, mutes -> mutex --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index 0808053e7..c3eb59c37 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -341,7 +341,7 @@ Here is a simplified version (the [standard library's][mutex] is more ergonomic): ~~~~rust -// create a new mutes +// create a new mutex fn mutex(t: T) -> Mutex; // acquire the lock From c21d868d58bf834a9d4ff5d06103263c89b07363 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 10 Apr 2015 09:50:51 -0700 Subject: [PATCH 069/386] Set up highlighting --- _config.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 8f9f594d4..ece89c2c2 100644 --- a/_config.yml +++ b/_config.yml @@ -9,6 +9,7 @@ twitter_username: rustlang github_username: rust-lang # Build settings -markdown: kramdown +highlighter: pygments +markdown: redcarpet root: http://blog.rust-lang.org From 35a85407f1880cd99e3a4679f3bc353e57d0965e Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 09:54:22 -0700 Subject: [PATCH 070/386] Adjust section headers to avoid code --- _posts/2015-04-10-Fearless-Concurrency.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index c3eb59c37..29f180a3f 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -422,7 +422,7 @@ access(&mut guard) Disaster averted. -### Thread safety and `Send` +### Thread safety and "Send" It's typical to distinguish some data types as "thread safe" and others not. Thread safe data structures use enough internal @@ -473,7 +473,7 @@ compiler will say: Disaster averted. -### Sharing the stack: `scoped` +### Sharing the stack: "scoped" So far, all the patterns we've seen involve creating data structures on the heap that get shared between threads. But what if we wanted to From 2e1b32ae1e8a1a2a655e070d0164d59b56609f99 Mon Sep 17 00:00:00 2001 From: Chas Date: Fri, 10 Apr 2015 10:17:07 -0700 Subject: [PATCH 071/386] Fixed typo in 2015-04-10-Fearless-Concurrency.md lock-fee should be lock-free --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index 29f180a3f..e0d089c0c 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -50,7 +50,7 @@ Here's a taste of concurrency in Rust: guaranteed safe in Rust**. All of these benefits come out of Rust's ownership model, and in fact -locks, channels, lock-fee data structures and so on are defined in +locks, channels, lock-free data structures and so on are defined in libraries, not the core language. That means that Rust's approach to concurrency is *open ended*: new libraries can embrace new paradigms and catch new bugs, just by adding APIs that use Rust's ownership From 3791406dda9ef9c0327ee8e35a0b54a4718850ed Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 10:43:29 -0700 Subject: [PATCH 072/386] Fix uncapitalized letter --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index c3eb59c37..ec5139013 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -459,7 +459,7 @@ the necessary synchronization here." Naturally, `Arc` is `Send`, and `Rc` is not. We already saw that the `Channel` and `Mutex` APIs work only with -`Send` data. since they are the point at which data crosses thread +`Send` data. Since they are the point at which data crosses thread boundaries, they are also the point of enforcement for `Send`. Putting this all together, Rust programmers can reap the benefits of From 92e8e6994fa8fdd95afac0c202c1de26f342340b Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 10 Apr 2015 10:54:16 -0700 Subject: [PATCH 073/386] Add missing semicolon --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index c3eb59c37..8d7065c06 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -547,7 +547,7 @@ fn parent() { // fill the vector let guard = thread::scoped(|| { print_vec(&vec) - }) + }); // guard destroyed here, implicitly joining } ~~~~ From 55b7f97982c52369f8f04517959307409ff62aa6 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Fri, 10 Apr 2015 15:57:10 -0400 Subject: [PATCH 074/386] spelling fix --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index b71001836..e9ce1aa3c 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -491,7 +491,7 @@ fn parent() { ~~~~ The child thread take a reference to `vec`, which in turn resides in -the stack frame of `parent`. When `parent` exists, the stack frame is +the stack frame of `parent`. When `parent` exits, the stack frame is popped, but the child thread is none the wiser. Oops! To rule out such memory unsafety, Rust's basic thread spawning API From c2472886b715b4664654d2997637e3b0bfe1092f Mon Sep 17 00:00:00 2001 From: Daniel Hackney Date: Fri, 10 Apr 2015 15:15:53 -0700 Subject: [PATCH 075/386] Remove redundant verb "How do you do make ..." doesn't make sense. Dropping the "do" fixes the sentence. --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index e9ce1aa3c..4e7635eae 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -8,7 +8,7 @@ description: "Rust's vision for concurrency" The Rust project was initiated to solve two thorny problems: * How do you do safe systems programming? -* How do you do make concurrency painless? +* How do you make concurrency painless? Initially these problems seemed orthogonal, but to our amazement, the solution turned out to be identical: **the same tools that make Rust From 662fbcfb4a605cc879bb077e10d402001c47a347 Mon Sep 17 00:00:00 2001 From: Will Hipschman Date: Fri, 10 Apr 2015 17:41:52 -0700 Subject: [PATCH 076/386] Fearless Concurrency Typo This 's' was lost, but now it's home again. --- _posts/2015-04-10-Fearless-Concurrency.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index 4e7635eae..29f10090a 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -490,7 +490,7 @@ fn parent() { } ~~~~ -The child thread take a reference to `vec`, which in turn resides in +The child thread takes a reference to `vec`, which in turn resides in the stack frame of `parent`. When `parent` exits, the stack frame is popped, but the child thread is none the wiser. Oops! From d73904ee399cb5cec7ee215b2df5117aacb8d6e0 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 8 Apr 2015 18:24:35 +0200 Subject: [PATCH 077/386] first draft of enums post. --- ...15-04-17-Enums-match-mutation-and-moves.md | 734 ++++++++++++++++++ 1 file changed, 734 insertions(+) create mode 100644 _posts/2015-04-17-Enums-match-mutation-and-moves.md diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md new file mode 100644 index 000000000..2ee059374 --- /dev/null +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -0,0 +1,734 @@ +--- +layout: post +title: "Enums: match, mutation, and moves" +author: Felix S. Klock II +description: "A tour of enums in Rust." +--- + +In this post we explore one corner of the Rust language: defining a +class of data via `enum`, and processing instances of such data via +`match`. + +Most of the post will use a single running example: modeling a game of +chess. At the end the post changes gears, shifting to a discussion of +how affine-typing ensures that the demonstrated features do not +introduce unsoundness. + +## Tutorial material + +The post takes the overall form of a tutorial. + +If you are already familiar with defining `enums` and simple uses of +`match`, you may want to skip ahead to the [mutating enums] or +[avoiding unsoundness] sections. This first section is meant to +establish everything one would need to know about enums to understand +the discussion in latter two sections. + +[mutating enums]: #mutating-enums +[avoiding unsoundness]: #avoiding-unsoundness + +### Defining simple enums + +The pieces of chess can be classified as follows: + +```rust +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum PieceShape { + King, Queen, Rook, Bishop, Knight, Pawn, +} +``` + +The `derive` line automatically generates support for three common +operations: the `Copy, Clone` gives us the ability to freely copy or +clone instances of `PieceShape`, the `Debug` provides support for +printing each piece-rank into an output buffer, e.g. via +`println!("piece: {:?}", piece)`, and `PartialEq, Eq` provides support +for the `==` operator on instances of the enum. + +### Enum discriminant values + +An enum like `PieceShape` above, where each variant is just a name, is +represented using an integer value for each variant. The definition +style above allows the Rust compiler to assign the values itself; it +will start from 0 and count upwards. + +Alternatively, one can manually assign specific values to enum +variants, interrupting the automatic value assignment performed by the +compiler. Thus, we could instead have written the below, and get the +same assignment of discriminant values: + +```rust +#[cfg(alternative)] +#[derive(Copy, Clone, Debug)] +pub enum PieceShape { + Pawn = 5, Rook = 2, Bishop, Knight, King = 0, Queen, +} +``` + +These enums, where each variant is just a name with an associated +(implicitly- or explicitly-assigned) integer value, are known as +"C-style enums" in Rust parlance, since the syntax largely matches +that used for the `enum` construct in the C language. + +(However, note that not every C enum immediately corresponds to an +analogous enum in Rust; in particular, Rust enforces an invariant that +each variant be distinct from all other variants in the enum, while C +allows one to assign the same integer value to multiple enum +variants.) + +### Constructing enum instances + +After defining an enum, one accesses the variants it defines via the +path syntax `enum_name::variant_name`. So using these pieces is +straight-forward enough: + +```rust +#[test] +fn demo_debug_format() { + let q = PieceShape::Queen; + let p = PieceShape::Pawn; + let k = PieceShape::King; + println!("q={:?} p={:?} k={:?}", q, p, k); +} +``` + +Of course, it can be annoying to have to type the enum name +repeatedly. To make the variants directly accessibly, import +them via `use`. + +```rust +#[test] +fn demo_debug_format_2() { + use self::PieceShape::{Queen, Pawn, King}; + let q = Queen; + let p = Pawn; + let k = King; + println!("q={:?} p={:?} k={:?}", q, p, k); +} +``` + +or even more simply: + +```rust +use self::PieceShape::*; +``` + +(Note that we have used `use self::...` here; the `use`-import syntax +resolves paths relative to the crate-root by default, but the leading +`self` changes the mode so that the resolution is relative to the +containing module.) + +### Destructuring enums via `match` + +Once we have created enum instances, we can process them via `match` +expressions. Here, we map each piece rank to a single letter code. + +```rust +pub fn one_letter(r: PieceShape) -> char { + match r { + Pawn => 'P', + Rook => 'R', + Knight => 'N', + Bishop => 'B', + Queen => 'Q', + King => 'K', + } +} + +#[test] +fn demo_one_letter() { + assert_eq!(one_letter(Queen), 'Q'); +} +``` + +Or as a more complex example, we can gather a sequence of shapes into a +character string: + +```rust +#[test] +fn demo_one_letter_collect() { + let qpk = [Queen, Pawn, King]; + let qpk: String = qpk.iter().map(|r|{one_letter(*r)}).collect(); + assert_eq!(qpk, "QPK"); +} +``` + +Encoding shapes via ASCII characters has worked fine since the 1960's, +but since we live in a more modern age, it is tempting to find out +whether we could encode our pieces with Unicode pictorial symbols. + +Indeed, reviewing the Unicode character charts, we discover that the +chess pieces have dedicated characters, but we see that there are +twelve such characters (starting from `U+2654`, "WHITE CHESS KING"), +not six. This reveals an oversight in our data description thus far: +We have represented shapes, but not the *color* of the piece. + +### Enums with payloads + +Here is one way of many to add color to our pieces, via a new `enum` +which represents one square of a chess board. + +```rust +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +enum Piece { + Black(PieceShape), + White(PieceShape), +} +``` + +This demonstrates a twist on `enum` that Rust provides. +Unlike an `enum` in C, which can only define a collection of names, +each variant of a Rust enum can optionally carry a payload of data. + +### Matching tree-structured patterns + +With this in hand, we can render a piece in a manner similar to how we +converted a shape to a letter in `one_letter` above. + +```rust +fn render(p: Piece) -> char { + match p { + Piece::White(King) => '\u{2654}', + Piece::White(Queen) => '\u{2655}', + Piece::White(Rook) => '\u{2656}', + Piece::White(Bishop) => '\u{2657}', + Piece::White(Knight) => '\u{2658}', + Piece::White(Pawn) => '\u{2659}', + + Piece::Black(King) => '\u{265A}', + Piece::Black(Queen) => '\u{265B}', + Piece::Black(Rook) => '\u{265C}', + Piece::Black(Bishop) => '\u{265D}', + Piece::Black(Knight) => '\u{265E}', + Piece::Black(Pawn) => '\u{265F}', + } +} + +#[test] +fn demo_render() { + let row = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook]; + let black_row: String = row.iter().map(|s| render(Piece::Black(*s))).collect(); + let white_row: String = row.iter().map(|s| render(Piece::White(*s))).collect(); + println!("black_row: {}", black_row); + println!("white_row: {}", white_row); +} +``` + +The `demo_render` test prints: + +``` +black_row: ♜♞♝♛♚♝♞♜ +white_row: ♖♘♗♕♔♗♘♖ +``` + +which is well on its way to a fully-rendered chess board. + +### Binding in match patterns + +Here is an alternative way to write the `render` function. + +```rust +fn render_2(p: Piece) -> char { + use std::char; + let offset = match p { + Piece::White(shape) => shape as u32, + Piece::Black(shape) => shape as u32, + }; + let king_unicode_value = match p { + Piece::White(_) => 0x2654, + Piece::Black(_) => 0x265A, + }; + char::from_u32(king_unicode_value + offset).unwrap() +} + +#[test] +fn check_renders() { + for &r in &[King, Queen, Rook, Bishop, Knight, Pawn] { + assert_eq!(render(Piece::White(r)), + render_2(Piece::White(r))); + assert_eq!(render(Piece::Black(r)), + render_2(Piece::Black(r))); + } +} +``` + +The above code illustrates a collection of features: + + * Rather than matching it as constant, one can bind the payload + attached to a enum-variant to an identifier. Thus the patterns in + the first `match` expression are each binding `shape` to the + corrresponding shape-payload attached to the piece. + + * One can cast a C-style enum value to the integer value used to + represent it, via the syntax `enum_value as integer_type`. + + * One can use `_` to ignore substructure in a pattern. This is used + in the second match expression, so that the shape held in `p` is + left in place. (This does not matter too much since `Shape` + implements `Copy`; it is often more important in cases where the + payload is not copyable, as further discussed below.) + +Thus, the `White` and `Black` `match`-clauses in the above code bind +`shape` to the associated `PieceShape`, and then casts that shape to +the appropriate integer offset from the king in the unicode codepoint +assignment. (The integers in our original enum definition for +`PieceShape` were selected so that they would match the sequence of +piece ranks in the unicode codepoint assignment.) + +## Mutating enums + +One event that occurs in chess is that when a pawn reaches the eighth +rank of the board, it is promoted to a another piece of the same color +(usually a queen). + +It is easy to write such a promotion in a functional programming +style: + +```rust +fn promote_to_queen_functional(p: Piece) -> Piece { + match p { + Piece::Black(_) => Piece::Black(Queen), + Piece::White(_) => Piece::White(Queen), + } +} + +#[test] +fn demo_promote_functional() { + let p = Piece::White(Pawn); + assert_eq!(promote_to_queen_functional(p), Piece::White(Queen)); +} +``` + +Let us imagine, however, that we want to model an actual chess board, +and we want to implement promotion as an *in-place* modification; that +is, instead of constructing a whole new copy of the board, we want to +instead use an imperative update to represent the promotion. + +### A first bumbling attempt + +Here is a first, admittedly bumbling, attempt to implement in-place +promotion from a pawn to a queen: It just removes the `-> Piece` +return type and shoehorns an assignment into the code, in the hopes +that everything will work out. + +So, first try: + +```rust +#[cfg(promote_attempt_1)] +fn promote_to_queen_1(mut pawn: Piece) { + pawn = match pawn { + Piece::Black(_) => Piece::Black(Queen), + Piece::White(_) => Piece::White(Queen), + }; +} + +#[cfg(promote_attempt_1)] +#[test] +fn demo_promote_1() { + let p = Piece::White(Pawn); + assert_eq!(p, Piece::White(Pawn)); + promote_to_queen_1(p); + assert_eq!(p, Piece::White(Queen)); +} +``` + +Compiling this (enabling it via `--cfg promote_attempt_1`) yields: + +``` +enums.rs:238:5: 238:9 warning: value assigned to `pawn` is never read, #[warn(unused_assignments)] on by default +enums.rs:238 pawn = match pawn { + ^~~~ +``` + +So that's not a good sign. Then running it yields: + +``` +test demo_promote_1 ... FAILED + +failures: + +---- demo_promote_1 stdout ---- +thread 'demo_promote_1' panicked at 'assertion failed: `(left == right)` (left: `White(Pawn)`, right: `White(Queen)`)', enums.rs:250 +``` + +This demonstrates, among other things, that static analysis cannot +stop someone who is determined to write buggy code. But the assertion +failure message is fairly clear about what the problem is: We had +hoped the piece `p` would be replaced with a queen, but it is in fact +still a pawn. + +The crucial mistake being made here is that if you want to mutate a +piece of state in place, then you need to have a mutable *reference* +to that state. The `mut pawn` formal argument to `promote_to_queen` is +indeed mutable, but those mutations are not visible from outside the +function, because the argument has already been moved into the +parameter's location. The invocation `promote_to_queen` is not passing +a reference (mutable or otherwise) to `p`; it is creating a *copy* of +the `Piece`. + +### A second stumble, caught at compile-time + +To make this really concrete, let us consider another kind of data in +our chess board. A chess board is made up of squares, usually +arranged in an 8-by-8 grid. Each `Square` is either unoccupied +(`Empty`) or is occupied by a single piece. + +```rust +#[derive(Clone, Debug, PartialEq, Eq)] +enum Square { + Empty, + Occupied(Piece), +} +``` + +Note that we have left off the `Copy` derivation; the intention is +that while `Rank` and `Piece` can be freely copied via assignment +statements, the square on a chess board has its own identity, and +should not be freely copied via assignment statements. + +With that in mind, let us try writing `promote_to_queen` again, but +this time passing in a `Square`. + +(This example is also taking advantage of another feature of Rust's +`match` syntax: one can combine multiple match arms that have +identical code into one arm by writing all their patterns pairwise +separated by a vertical bar (`|`)): + + +```rust +#[cfg(promote_attempt_2)] +fn promote_to_queen_2(mut s: Square) { + match s { + Square::Empty => {} + Square::Occupied(Piece::White(mut shape)) | + Square::Occupied(Piece::Black(mut shape)) => { + shape = Queen + } + } +} + +#[cfg(promote_attempt_2)] +#[test] +fn demo_promote_2() { + let mut s = Square::Occupied(Piece::White(Pawn)); + promote_to_queen_2(s); + assert_eq!(s, Square::Occupied(Piece::White(Queen))); +} +``` + +This second attempt has the same mistake that we made with +`promote_to_queen_2`: we again have failed to take a mutable reference +to the square, so no in-place update is possible. But *now* we get a +compile-time error: + +``` +:3:11: 3:23 error: use of moved value: `s` +:3 match ( & ( $ left ) , & ( $ right ) ) { + ^~~~~~~~~~~~ +:1:1: 9:39 note: in expansion of assert_eq! +enums.rs:319:5: 319:58 note: expansion site +enums.rs:318:24: 318:25 note: `s` moved here because it has type `Square`, which is non-copyable +enums.rs:318 promote_to_queen_2(s); + ^ +``` + +The error message is telling us exactly what happened: the argument to +`promote_to_queen_2` is moved when the function is called; thus the +attempt to reference `s` in the `assert_eq!` invocation fails, because +`s` has been moved. + +(This illustrates why one might *not* add `derive(Copy)` to every data +type where it would otherwise be legal; leaving out `derive(Copy)` can +catch certain bugs.) + +### Try, try again; taking a reference + +So, here's a third try, where we take a reference to the `Square`. + +```rust +#[cfg(promote_attempt_3)] +fn promote_to_queen_3(s: &mut Square) { + match s { + &mut Square::Empty => {} + &mut Square::Occupied(Piece::White(mut shape)) | + &mut Square::Occupied(Piece::Black(mut shape)) => { + shape = Queen + } + } +} + +#[cfg(promote_attempt_3)] +#[test] +fn demo_promote_3() { + let mut p = Square::Occupied(Piece::White(Pawn)); + promote_to_queen_3(&mut p); + assert_eq!(p, Square::Occupied(Piece::White(Queen))); +} +``` + +We again see the warning: + +``` +enums.rs:355:44: 355:49 warning: variable `shape` is assigned to, but never used, #[warn(unused_variables)] on by default +enums.rs:355 &mut Square::Occupied(Piece::White(mut shape)) | + ^~~~~~~~~ +enums.rs:357:13: 357:14 warning: value assigned to `shape` is never read, #[warn(unused_assignments)] on by default +enums.rs:357 shape = Queen + ^~~~~ +``` + +This warning is again warranted, as the test fails: + +``` +test demo_promote_3 ... FAILED + +failures: + +---- demo_promote_3 stdout ---- +thread 'demo_promote_3' panicked at 'assertion failed: `(left == right)` (left: `Occupied(White(Pawn))`, right: `Occupied(White(Queen))`)', enums.rs:367 +``` + +### Keeping `ref`s into referenced data + +So, what happened here? + +The answer is: Even though we have ensured that `Square` is not +accidentally copied, there is nothing stopping the *contents* of +`Square` from being copied. So in a `match` arm like +``` +&mut Square::Occupied(Piece::Black(mut shape)) => { ... } +``` +if the discriminant value matches that arm, then it will put a +copy of its shape into `shape`. + +This brings us to a very important point about how `match` works in +Rust: it matches its inputs in-place, but normal bindings like the +`mut shape` above will move (or copy) the matched substructure into +fresh locations. + +If you want to capture a reference into the matched substructure, +either to avoid extraneous copying, or to enable modification of the +original input value, then you need to use a `ref`-pattern. + +With this knowledge in hand, let us try again. + +In addition, our fourth try simplifies the code slightly by +dereferencing the argument `*s`. + +```rust +fn promote_to_queen_4(s: &mut Square) { + match *s { + Square::Empty => {} + Square::Occupied(Piece::White(ref mut shape)) | + Square::Occupied(Piece::Black(ref mut shape)) => { + *shape = Queen + } + } +} + +#[test] +fn demo_promote_4() { + let mut p = Square::Occupied(Piece::White(Pawn)); + promote_to_queen_4(&mut p); + assert_eq!(p, Square::Occupied(Piece::White(Queen))); +} +``` + +Compiling and running our code now yields: + +``` +running 7 tests +test demo_debug_format ... ok +test demo_one_letter_collect ... ok +test demo_one_letter ... ok +test demo_debug_format_2 ... ok +test demo_promote_4 ... ok +test check_renders ... ok +test demo_promote_functional ... ok + +test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured +``` + +Huzzah, it works! + +The dereference `*s` works because `match` works on both "L-value" and +"R-value" expressions; L-value expressions evaluate to memory +locations, while R-value expressions evaluate to values that are then +stored, if necessary, in temporary memory locations. It simplified our +code because allowed us to sidestep writing `&mut` at the beginning of +each of our patterns, which was not such a great burden for this tiny +code snippet, but can be much more annoying when working with `match` +expressions that have many more arms, amplifying the redundancy. + +## Avoiding unsoundness + +(This section is adapted from the Rust demo we presented at the 2014 +ML workshop.) + +A potentially non-obvious issue arises when a supposedly-sound +language adds support for `ref mut`, or even just `ref`, in a +non-moving/non-copying `match` expression: How does one prevent +someone from injecting unsound behavior by using mutable references to +overwrite state secretly, subverting the type-system? + +Consider the following code: + +```rust +#[test] +fn sound_code() { + enum E { A(fn (i8) -> i8), B(usize) } + fn add3(x:i8) -> i8 { x + 3 } + let mut a = E::A(add3); let mut b = E::B(19); + { + let m1 = &mut a; let m2 = &mut b; + foo(m1, m2); + } + match b { + E::A(_fn) => println!("b is an E::A"), + E::B(val) => println!("b is an E::B: 0x{:x}", val), + } + + fn foo(p1: &mut E, p2: &mut E) { + match p1 { + &mut E::B(..) => panic!("cannot happen"), + &mut E::A(ref adder) => { + /* WATCH: */ *p2 = E::B(0xBadC0de); + println!("{}", (*adder)(14)); + } + } + } +} +``` + +The above compiles and runs just fine: the references to `a` and `b` +are copied to `p1` and `p2` respectively for the call to `foo`, `b` is +imperatively updated via `p2`, `foo` prints out `17` (= 14 + 3), and +then after `foo` returns it prints out `b is an E::B: 0xbadc0de`. + +The question is: what happens when we tweak the test slightly? + +### Attempted subversion via local overwrites + +For example, what if we imperatively modify `*p1` instead of `*p2`, +but leave the code otherwise unchanged? + +Storing the `E::B(0xBadCode)` would invalidate the data held in +`adder` (indeed, it would put "bad code" there), and so the subsequent +invocation of `adder` will jump to some (potentially invalid) memory +location and try to interpret it as executable code. + +But watch: + +```rust +#[cfg(wont_compile)] +#[test] +fn unsound_code_1() { + enum E { A(fn (i8) -> i8), B(usize) } + fn add3(x:i8) -> i8 { x + 3 } + let mut a = E::A(add3); let mut b = E::B(19); + { + let m1 = &mut a; let m2 = &mut b; + foo(m1, m2); + } + match b { + E::A(_fn) => println!("b is an E::A"), + E::B(val) => println!("b is an E::B: 0x{:x}", val), + } + + fn foo(p1: &mut E, p2: &mut E) { + match p1 { + &mut E::B(..) => panic!("cannot happen"), + &mut E::A(ref adder) => { + /* was p2 */ *p1 = E::B(0xBadC0de); + println!("{}", (*adder)(14)); + } + } + } +} +``` + +As you might have inferred from the `cfg` annotation above, this +will not compile. Attempting to compile it yields: + +``` +enums.rs:569:30: 569:51 error: cannot assign to `*p1` because it is borrowed +enums.rs:569 /* was p2 */ *p1 = E::B(0xBadC0de); + ^~~~~~~~~~~~~~~~~~~~~ +enums.rs:568:23: 568:32 note: borrow of `*p1` occurs here +enums.rs:568 &mut E::A(ref adder) => { + ^~~~~~~~~ +``` + +So, the compiler prevents us from overwriting the function pointer +with bogus data! (Of course, if you *really* want to shoot yourself in +the foot, you can resort to `unsafe` code to sneak the overwrite +through; at that point you are explicitly side-stepping the type +system, which Rust allows.) + +### Attempted subversion via aliasing + +Furthermore, the same rules that prevented the last example from +compiling are not performing a local check of just the single function +`foo`; they are enforcing a *global* soundness property. Other +non-local attempts to subvert the type system by sneaking the +overwrite past the static checks are foiled, as shown here: + +```rust +#[cfg(wont_compile)] +#[test] +fn unsound_code_2() { + enum E { A(fn (i8) -> i8), B(usize) } + fn add3(x:i8) -> i8 { x + 3 } + let mut a = E::A(add3); let mut b = E::B(19); + { + let m1 = &mut a; let m2 = &mut b; + foo(m1, m1); + } + match b { + E::A(_fn) => println!("b is an E::A"), + E::B(val) => println!("b is an E::B: 0x{:x}", val), + } + + fn foo(p1: &mut E, p2: &mut E) { + match p1 { + &mut E::B(..) => panic!("cannot happen"), + &mut E::A(ref adder) => { + /* watch? */ *p2 = E::B(0xBadC0de); + println!("{}", (*adder)(14)); + } + } + } +} +``` + +The above is attempting to create an *alias* between `p1` and `p2`, +thus causing the write to `p2` to actually overwrite the data +we matched in `p1`. + +However, this example also fails to compile: + +``` +enums.rs:612:17: 612:19 error: cannot borrow `*m1` as mutable more than once at a time +enums.rs:612 foo(m1, m1); + ^~ +enums.rs:612:13: 612:15 note: previous borrow of `*m1` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*m1` until the borrow ends +enums.rs:612 foo(m1, m1); + ^~ +enums.rs:612:20: 612:20 note: previous borrow ends here +enums.rs:612 foo(m1, m1); + ^ +``` + +This illustrates why Rust takes such pains to support affine typing of +`&mut T` and other owned types: It is necessary for type soundness! + +## Conclusion + +Thus ends our tour of enums in Rust. For more information on details +that were not covered here, such as binding via `ident @ pattern`, or +the potentially subtle difference between `{ let id = expr; ... }` +versus `match expr { id => { ... } }`, consult the Rust documentation, +or quiz our awesome community (in `#rust` on IRC, or in the +[user group]). + +[user group]: http://users.rust-lang.org/ From cd513f361bcfdc24d18d9340b8041d67d0a94129 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 9 Apr 2015 15:15:59 +0200 Subject: [PATCH 078/386] Added note about the `cfg(alternative)`. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 2ee059374..6aa5ba810 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -65,6 +65,12 @@ pub enum PieceShape { } ``` +(In the above, the `cfg` line is how one denotes "conditional +compilation" in Rust; it indicates that the `enum` definition beneath +it should only be compiled if one passes `--cfg alternative` to the +invocation of `rustc`; it is being used above as a quick-and-dirty way +to avoid causing a compile-time error with a duplicate definition.) + These enums, where each variant is just a name with an associated (implicitly- or explicitly-assigned) integer value, are known as "C-style enums" in Rust parlance, since the syntax largely matches From 5a2f10c070c23fa63925e000f379f6c4132e5452 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Wed, 15 Apr 2015 16:47:14 +0200 Subject: [PATCH 079/386] second draft. near complete rewrite. --- ...15-04-17-Enums-match-mutation-and-moves.md | 877 +++++++++--------- 1 file changed, 413 insertions(+), 464 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6aa5ba810..318d36754 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -1,572 +1,520 @@ --- layout: post -title: "Enums: match, mutation, and moves" +title: "Mixing matching, mutation, and moves in Rust" author: Felix S. Klock II -description: "A tour of enums in Rust." +description: "A tour of matching and enums in Rust." --- -In this post we explore one corner of the Rust language: defining a -class of data via `enum`, and processing instances of such data via -`match`. +One of the primary goals of the Rust project is to enable safe systems +programming. Systems programming usually implies imperative +programming, which in turns often implies side-effects, reasoning +about shared, aliasable state, et cetera. -Most of the post will use a single running example: modeling a game of -chess. At the end the post changes gears, shifting to a discussion of -how affine-typing ensures that the demonstrated features do not -introduce unsoundness. +At the same time, to provide *safety*, Rust programs and data types +must be structured in a way that allows static checking to ensure +soundness. Rust has features and restrictions that operate in tandem +to ease writing programs that can pass these checks and thus ensure +safety. For example, Rust incorporates the notion of *ownership* deeply +into the language. -## Tutorial material +Rust's `match` expression is a construct that offers an interesting +combination of such features and restrictions. A `match` expression +takes an input value, classifies it, and then jumps to code written to +handle the identified class of data. -The post takes the overall form of a tutorial. +In this post we explore how Rust processes such data via `match`. +The crucial elements that `match` and its counterpart `enum` tie +together are: -If you are already familiar with defining `enums` and simple uses of -`match`, you may want to skip ahead to the [mutating enums] or -[avoiding unsoundness] sections. This first section is meant to -establish everything one would need to know about enums to understand -the discussion in latter two sections. +* Exhaustive case analysis, which ensures that no case is omitted + when processing an input. -[mutating enums]: #mutating-enums -[avoiding unsoundness]: #avoiding-unsoundness +* `match` embraces both imperative and applicative styles of + programming. The compiler's static analyses work hard to ensure + statement-oriented programming remains palatable, leaving the + question of whether expression-orientation is better to style + guides. -### Defining simple enums +* Destructuring bind of *L-values*: Rust encourages the developer to + think carefully about ownership and borrowing. To ensure that + processing data does not force one to give up ownership of a value + prematurely, `match` is designed with support for merely *borrowing* + substructure within its input (as opposed to always *moving* such + substructure). -The pieces of chess can be classified as follows: +We cover each of the items above in detail below, but first we +establish a foundation for the discussion: What does `match` look +like, and how does it work? -```rust -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum PieceShape { - King, Queen, Rook, Bishop, Knight, Pawn, -} -``` - -The `derive` line automatically generates support for three common -operations: the `Copy, Clone` gives us the ability to freely copy or -clone instances of `PieceShape`, the `Debug` provides support for -printing each piece-rank into an output buffer, e.g. via -`println!("piece: {:?}", piece)`, and `PartialEq, Eq` provides support -for the `==` operator on instances of the enum. +### The Basics of `match` -### Enum discriminant values - -An enum like `PieceShape` above, where each variant is just a name, is -represented using an integer value for each variant. The definition -style above allows the Rust compiler to assign the values itself; it -will start from 0 and count upwards. - -Alternatively, one can manually assign specific values to enum -variants, interrupting the automatic value assignment performed by the -compiler. Thus, we could instead have written the below, and get the -same assignment of discriminant values: +The `match` expression in Rust has this form: ```rust -#[cfg(alternative)] -#[derive(Copy, Clone, Debug)] -pub enum PieceShape { - Pawn = 5, Rook = 2, Bishop, Knight, King = 0, Queen, +match INPUT_EXPRESSION { + PREDICATE_1 => RESULT_EXPRESSION_1, + PREDICATE_2 => RESULT_EXPRESSION_2, + ... + PREDICATE_n => RESULT_EXPRESSION_n } ``` -(In the above, the `cfg` line is how one denotes "conditional -compilation" in Rust; it indicates that the `enum` definition beneath -it should only be compiled if one passes `--cfg alternative` to the -invocation of `rustc`; it is being used above as a quick-and-dirty way -to avoid causing a compile-time error with a duplicate definition.) +where each of the `PREDICATE_i` contains at least one *pattern*. A +pattern describes a subset of the possible values to which +`INPUT_EXPRESSION` could evaluate. +The syntax `PREDICATE => RESULT_EXPRESSION` is called a "match arm", +or simply "arm". -These enums, where each variant is just a name with an associated -(implicitly- or explicitly-assigned) integer value, are known as -"C-style enums" in Rust parlance, since the syntax largely matches -that used for the `enum` construct in the C language. +Patterns can match atomic values, like integers or characters; they +can also match user-defined symbolic data, defined via `enum`. -(However, note that not every C enum immediately corresponds to an -analogous enum in Rust; in particular, Rust enforces an invariant that -each variant be distinct from all other variants in the enum, while C -allows one to assign the same integer value to multiple enum -variants.) +The below code demonstrates generating the next guess (poorly) in a number +guessing game, given the answer from a previous guess. -### Constructing enum instances +(Incidentally, nearly all the code in this post is directly +executable; you can cut-and-paste the code snippets into a file +`demo.rs`, compile the file with `--test`, and run the resulting +binary to see the tests run.) -After defining an enum, one accesses the variants it defines via the -path syntax `enum_name::variant_name`. So using these pieces is -straight-forward enough: - -```rust -#[test] -fn demo_debug_format() { - let q = PieceShape::Queen; - let p = PieceShape::Pawn; - let k = PieceShape::King; - println!("q={:?} p={:?} k={:?}", q, p, k); +```rust,code +enum Answer { + Higher, + Lower, + Bingo, } -``` -Of course, it can be annoying to have to type the enum name -repeatedly. To make the variants directly accessibly, import -them via `use`. +fn suggest_guess(prior_guess: u32, answer: Answer) { + match answer { + Answer::Higher => println!("maybe try {} next", prior_guess + 10), + Answer::Lower => println!("maybe try {} next", prior_guess - 1), + Answer::Bingo => println!("we won with {}!", prior_guess), + } +} -```rust #[test] -fn demo_debug_format_2() { - use self::PieceShape::{Queen, Pawn, King}; - let q = Queen; - let p = Pawn; - let k = King; - println!("q={:?} p={:?} k={:?}", q, p, k); +fn demo_suggest_guess() { + suggest_guess(10, Answer::Higher); + suggest_guess(20, Answer::Lower); + suggest_guess(19, Answer::Bingo); } ``` -or even more simply: - -```rust -use self::PieceShape::*; -``` +Patterns can also match structured data (e.g. tuples, slices, user-defined +data types) via corresponding patterns. In such patterns, one often +binds substructure of the input to local variables (identifer patterns), +for use either in the arm's predicate or in its result. -(Note that we have used `use self::...` here; the `use`-import syntax -resolves paths relative to the crate-root by default, but the leading -`self` changes the mode so that the resolution is relative to the -containing module.) +The special `_` pattern matches any single value, and is often used as +a catch-all; the special `..` pattern generalizes this by matching any +*series* of values or name/value pairs. -### Destructuring enums via `match` +Also, one can collapse multiple patterns into one arm by separating the +patterns by vertical bars (`|`); thus that arm matches either this pattern, +or that pattern, et cetera. -Once we have created enum instances, we can process them via `match` -expressions. Here, we map each piece rank to a single letter code. +These features are illustrated in the following revision to the +guessing-game answer generation strategy: -```rust -pub fn one_letter(r: PieceShape) -> char { - match r { - Pawn => 'P', - Rook => 'R', - Knight => 'N', - Bishop => 'B', - Queen => 'Q', - King => 'K', - } +```rust,code +struct GuessState { + guess: u32, + answer: Answer, + low: u32, + high: u32, } -#[test] -fn demo_one_letter() { - assert_eq!(one_letter(Queen), 'Q'); +fn suggest_guess_smarter(s: GuessState) { + match s { + GuessState { answer: Answer::Bingo, guess: p, .. } => { + println!("we won with {}!", p); + } + GuessState { answer: Answer::Higher, guess: l, low: _, high: h } | + GuessState { answer: Answer::Lower, guess: h, low: l, high: _ } => { + let mid = l + ((h - l) / 2); + println!("lets try {} next", mid); + } + } } -``` - -Or as a more complex example, we can gather a sequence of shapes into a -character string: -```rust #[test] -fn demo_one_letter_collect() { - let qpk = [Queen, Pawn, King]; - let qpk: String = qpk.iter().map(|r|{one_letter(*r)}).collect(); - assert_eq!(qpk, "QPK"); +fn demo_guess_state() { + suggest_guess_smarter(GuessState { + guess: 20, answer: Answer::Lower, low: 10, high: 1000 + }); } ``` -Encoding shapes via ASCII characters has worked fine since the 1960's, -but since we live in a more modern age, it is tempting to find out -whether we could encode our pieces with Unicode pictorial symbols. - -Indeed, reviewing the Unicode character charts, we discover that the -chess pieces have dedicated characters, but we see that there are -twelve such characters (starting from `U+2654`, "WHITE CHESS KING"), -not six. This reveals an oversight in our data description thus far: -We have represented shapes, but not the *color* of the piece. +That is `match` in a nutshell. -### Enums with payloads +So, what is the interplay between this construct and Rust's approach to +ownership and safety in general? -Here is one way of many to add color to our pieces, via a new `enum` -which represents one square of a chess board. +### Exhaustive case analysis -```rust -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum Piece { - Black(PieceShape), - White(PieceShape), -} -``` +One important method of analytical thinking is case analysis: Dividing +a problem into some number of separate cases, and then analyzing each +case individually. -This demonstrates a twist on `enum` that Rust provides. -Unlike an `enum` in C, which can only define a collection of names, -each variant of a Rust enum can optionally carry a payload of data. +For this method of problem solving to work, the cases must be +*collectively exhaustive*; otherwise, a case that was not covered +would mean a potential problem instance for which no solution has been +identified. -### Matching tree-structured patterns +This brings us to one of the fundamental restrictions of Rust's +`match` construct: the collection of provided cases must be exhautive. -With this in hand, we can render a piece in a manner similar to how we -converted a shape to a letter in `one_letter` above. +So, for example, the following code is rejected at compile-time. ```rust -fn render(p: Piece) -> char { - match p { - Piece::White(King) => '\u{2654}', - Piece::White(Queen) => '\u{2655}', - Piece::White(Rook) => '\u{2656}', - Piece::White(Bishop) => '\u{2657}', - Piece::White(Knight) => '\u{2658}', - Piece::White(Pawn) => '\u{2659}', - - Piece::Black(King) => '\u{265A}', - Piece::Black(Queen) => '\u{265B}', - Piece::Black(Rook) => '\u{265C}', - Piece::Black(Bishop) => '\u{265D}', - Piece::Black(Knight) => '\u{265E}', - Piece::Black(Pawn) => '\u{265F}', - } -} - -#[test] -fn demo_render() { - let row = [Rook, Knight, Bishop, Queen, King, Bishop, Knight, Rook]; - let black_row: String = row.iter().map(|s| render(Piece::Black(*s))).collect(); - let white_row: String = row.iter().map(|s| render(Piece::White(*s))).collect(); - println!("black_row: {}", black_row); - println!("white_row: {}", white_row); +fn suggest_guess_broken(prior_guess: u32, answer: Answer) { + let next_guess = match answer { + Answer::Higher => prior_guess + 10, + Answer::Lower => prior_guess - 1, + // ERROR: non-exhaustive patterns: `Bingo` not covered + }; + println!("maybe try {} next", next_guess); } ``` -The `demo_render` test prints: - -``` -black_row: ♜♞♝♛♚♝♞♜ -white_row: ♖♘♗♕♔♗♘♖ -``` +Many other languages offer a pattern matching construct (ML and +various macro-based `match` implementations in Scheme both come to +mind), but not all of them have this restriction. -which is well on its way to a fully-rendered chess board. +Rust has this restriction for two reasons: -### Binding in match patterns +* First, as noted above, dividing a problem into cases only yields a +general solution if the cases are exhaustive. Exhaustiveness-checking +exposes logical errors. -Here is an alternative way to write the `render` function. +* Second, since `match` is an expression form, exhaustiveness ensures +that such expressions always evaluates to a value of the correct type +(or jump elsehwere in the program, as illustrated here): -```rust -fn render_2(p: Piece) -> char { - use std::char; - let offset = match p { - Piece::White(shape) => shape as u32, - Piece::Black(shape) => shape as u32, - }; - let king_unicode_value = match p { - Piece::White(_) => 0x2654, - Piece::Black(_) => 0x265A, +```rust,code +fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { + let next_guess = match answer { + Answer::Higher => prior_guess + 10, + Answer::Lower => prior_guess - 1, + Answer::Bingo => { + println!("we won!"); + return; + } }; - char::from_u32(king_unicode_value + offset).unwrap() + println!("maybe try {} next", next_guess); } #[test] -fn check_renders() { - for &r in &[King, Queen, Rook, Bishop, Knight, Pawn] { - assert_eq!(render(Piece::White(r)), - render_2(Piece::White(r))); - assert_eq!(render(Piece::Black(r)), - render_2(Piece::Black(r))); - } +fn demo_guess_fixed() { + suggest_guess_fixed(10, Answer::Higher); + suggest_guess_fixed(20, Answer::Lower); + suggest_guess_fixed(19, Answer::Bingo); } ``` -The above code illustrates a collection of features: - - * Rather than matching it as constant, one can bind the payload - attached to a enum-variant to an identifier. Thus the patterns in - the first `match` expression are each binding `shape` to the - corrresponding shape-payload attached to the piece. - - * One can cast a C-style enum value to the integer value used to - represent it, via the syntax `enum_value as integer_type`. - - * One can use `_` to ignore substructure in a pattern. This is used - in the second match expression, so that the shape held in `p` is - left in place. (This does not matter too much since `Shape` - implements `Copy`; it is often more important in cases where the - payload is not copyable, as further discussed below.) +### Both expression- and statement-oriented -Thus, the `White` and `Black` `match`-clauses in the above code bind -`shape` to the associated `PieceShape`, and then casts that shape to -the appropriate integer offset from the king in the unicode codepoint -assignment. (The integers in our original enum definition for -`PieceShape` were selected so that they would match the sequence of -piece ranks in the unicode codepoint assignment.) +Unlike many languages that offer pattern matching, Rust *embraces* +both statement- and expression-oriented programming. -## Mutating enums +Consider writing a function which maps a non-negative integer to a +string rendering it as an ordinal ("1st", "2nd", "3rd", ...). -One event that occurs in chess is that when a pawn reaches the eighth -rank of the board, it is promoted to a another piece of the same color -(usually a queen). +The following code uses range patterns to simplify things, but also, +it is written in a style similar to a `switch` in a statement-oriented +language like C (or C++, Java, et cetera), where the arms of the +`match` are executed for their side-effect alone: -It is easy to write such a promotion in a functional programming -style: - -```rust -fn promote_to_queen_functional(p: Piece) -> Piece { - match p { - Piece::Black(_) => Piece::Black(Queen), - Piece::White(_) => Piece::White(Queen), +```rust,code +fn num_to_ordinal(x: u32) -> String { + let suffix; + match (x % 10, x % 100) { + (1, 1) | (1, 21...91) => { + suffix = "st"; + } + (2, 2) | (2, 22...92) => { + suffix = "nd"; + } + (3, 3) | (3, 23...93) => { + suffix = "rd"; + } + _ => { + suffix = "th"; + } } + return format!("{}{}", x, suffix); } #[test] -fn demo_promote_functional() { - let p = Piece::White(Pawn); - assert_eq!(promote_to_queen_functional(p), Piece::White(Queen)); +fn test_num_to_ordinal() { + assert_eq!(num_to_ordinal( 0), "0th"); + assert_eq!(num_to_ordinal( 1), "1st"); + assert_eq!(num_to_ordinal( 12), "12th"); + assert_eq!(num_to_ordinal( 22), "22nd"); + assert_eq!(num_to_ordinal( 43), "43rd"); + assert_eq!(num_to_ordinal( 67), "67th"); + assert_eq!(num_to_ordinal(1901), "1901st"); } ``` -Let us imagine, however, that we want to model an actual chess board, -and we want to implement promotion as an *in-place* modification; that -is, instead of constructing a whole new copy of the board, we want to -instead use an imperative update to represent the promotion. - -### A first bumbling attempt - -Here is a first, admittedly bumbling, attempt to implement in-place -promotion from a pawn to a queen: It just removes the `-> Piece` -return type and shoehorns an assignment into the code, in the hopes -that everything will work out. - -So, first try: +The Rust compiler accepts the above program; this is notable because +its static analysis is ensuring both that `suffix` is always +initialized before we run the `format!` at the end *and* that `suffix` +is assigned at most once during the function's execution (because if +we could assign `suffix` multiple times, the compiler would force us +to mark `suffix` as mutable). + +To be clear, the above program certainly *can* be written in an +expression-oriented style. The point is that each of the styles has +its use cases, and switching to a statement-oriented style does not +sacrifice every other feature that Rust provides, such as ensuring +that a non-`mut` binding is assigned at most once. + +An important case where this arises is when one wants to +initialize some state and then borrow from it, but only on +*some* control-flow branches. + +```rust,code +fn sometimes_initialize(input: i32) { + let string; + let borrowed; + match input { + 0...100 => { + string = format!("input prints as {}", input); + borrowed = &string[6..]; + } + _ => { + borrowed = "expected between 0 and 100"; + } + } + println!("borrowed: {}", borrowed); -```rust -#[cfg(promote_attempt_1)] -fn promote_to_queen_1(mut pawn: Piece) { - pawn = match pawn { - Piece::Black(_) => Piece::Black(Queen), - Piece::White(_) => Piece::White(Queen), - }; + // (Below would cause compile-time error if uncommented.) + // println!("string: {}", string); } -#[cfg(promote_attempt_1)] #[test] -fn demo_promote_1() { - let p = Piece::White(Pawn); - assert_eq!(p, Piece::White(Pawn)); - promote_to_queen_1(p); - assert_eq!(p, Piece::White(Queen)); +fn demo_sometimes_initialize() { + sometimes_initialize(23); + sometimes_initialize(123); } ``` -Compiling this (enabling it via `--cfg promote_attempt_1`) yields: - -``` -enums.rs:238:5: 238:9 warning: value assigned to `pawn` is never read, #[warn(unused_assignments)] on by default -enums.rs:238 pawn = match pawn { - ^~~~ -``` - -So that's not a good sign. Then running it yields: - -``` -test demo_promote_1 ... FAILED - -failures: - ----- demo_promote_1 stdout ---- -thread 'demo_promote_1' panicked at 'assertion failed: `(left == right)` (left: `White(Pawn)`, right: `White(Queen)`)', enums.rs:250 -``` - -This demonstrates, among other things, that static analysis cannot -stop someone who is determined to write buggy code. But the assertion -failure message is fairly clear about what the problem is: We had -hoped the piece `p` would be replaced with a queen, but it is in fact -still a pawn. - -The crucial mistake being made here is that if you want to mutate a -piece of state in place, then you need to have a mutable *reference* -to that state. The `mut pawn` formal argument to `promote_to_queen` is -indeed mutable, but those mutations are not visible from outside the -function, because the argument has already been moved into the -parameter's location. The invocation `promote_to_queen` is not passing -a reference (mutable or otherwise) to `p`; it is creating a *copy* of -the `Piece`. - -### A second stumble, caught at compile-time - -To make this really concrete, let us consider another kind of data in -our chess board. A chess board is made up of squares, usually -arranged in an 8-by-8 grid. Each `Square` is either unoccupied -(`Empty`) or is occupied by a single piece. - -```rust -#[derive(Clone, Debug, PartialEq, Eq)] -enum Square { - Empty, - Occupied(Piece), +The interesting thing about the above code is that after the `match`, +we are not allowed to directly access `string`, because the compiler +requires that the variable be initialized on every path through the +program. At the same time, we *can* access the data that is held +*within* `string`, because a reference to that data is held by the +`borrowed` variable, which we ensure is initialized on every program +path. (The compiler ensures that no outstanding borrows of the +`string` data could possible outlive `string` itself, and the +generated code ensures that at the end of the scope of `string`, its +data is deallocated if it was previously initialized.) + +In short, for soundness, the Rust language ensures that data is always +initialized before it is referenced, but the designers have attempted +to not require artifices like dummy-initializations inserted solely to +placate such requirements. + +### Algebraic Data Types and Data Invariants + +An `enum` type allows one to define mutually-exclusive classes of +values. The examples shown above used `enum` for simple symbolic tags, +but in Rust, such definitions can define much richer classes of data. + +For example, a binary tree is either a leaf, or an internal node with +references to two child trees. Here is one way to encode a tree of +integers in Rust: + +```rust,code +enum BinaryTree { + Leaf(i32), + Node(Box, i32, Box) } ``` -Note that we have left off the `Copy` derivation; the intention is -that while `Rank` and `Piece` can be freely copied via assignment -statements, the square on a chess board has its own identity, and -should not be freely copied via assignment statements. - -With that in mind, let us try writing `promote_to_queen` again, but -this time passing in a `Square`. - -(This example is also taking advantage of another feature of Rust's -`match` syntax: one can combine multiple match arms that have -identical code into one arm by writing all their patterns pairwise -separated by a vertical bar (`|`)): - - -```rust -#[cfg(promote_attempt_2)] -fn promote_to_queen_2(mut s: Square) { - match s { - Square::Empty => {} - Square::Occupied(Piece::White(mut shape)) | - Square::Occupied(Piece::Black(mut shape)) => { - shape = Queen +(The `Box` type describes an owning reference to a heap-allocated +instance of `V`; if you own a `Box`, then you also own the `V` it +contains, and can mutate it, lend out references to it, et cetera, and +when you finish with the box and let it fall out of scope, it will +automatically clean up the resources associated with the +heap-allocated `V`.) + +The above definition ensures that if we are given a `BinaryTree`, it +will always fall into one of the above two cases. One will never +encounter a `BinaryTree::Node` that does not have a left-hand child. +There is no need to check for null. + +One *does* need to check whether a given `BinaryTree` is a `Leaf` or +az a `Node`, but the compiler statically ensure such checks are done: +you cannot accidentally interpret the data of a `Leaf` as if it were a +`Node`, nor vice versa. + +```rust,code +/// Sum of values in all the nodes and leaves of `t`. +fn tree_weight_v1(t: BinaryTree) -> i32 { + match t { + BinaryTree::Leaf(payload) => payload, + BinaryTree::Node(left, payload, right) => { + tree_weight_v1(*left) + payload + tree_weight_v1(*right) } } } -#[cfg(promote_attempt_2)] +/// Looks like: +/// +/// (4) +/// | +/// +--(2) +/// | | +/// | +--[1] +/// | | +/// | +--[3] +/// | +/// +--[5] +/// +fn sample_tree() -> BinaryTree { + let l1 = Box::new(BinaryTree::Leaf(1)); + let l3 = Box::new(BinaryTree::Leaf(3)); + let n2 = Box::new(BinaryTree::Node(l1, 2, l3)); + let l5 = Box::new(BinaryTree::Leaf(5)); + + BinaryTree::Node(n2, 4, l5) +} + #[test] -fn demo_promote_2() { - let mut s = Square::Occupied(Piece::White(Pawn)); - promote_to_queen_2(s); - assert_eq!(s, Square::Occupied(Piece::White(Queen))); +fn tree_demo_1() { + let tree = sample_tree(); + assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5); } ``` -This second attempt has the same mistake that we made with -`promote_to_queen_2`: we again have failed to take a mutable reference -to the square, so no in-place update is possible. But *now* we get a -compile-time error: +### Matching L-values -``` -:3:11: 3:23 error: use of moved value: `s` -:3 match ( & ( $ left ) , & ( $ right ) ) { - ^~~~~~~~~~~~ -:1:1: 9:39 note: in expansion of assert_eq! -enums.rs:319:5: 319:58 note: expansion site -enums.rs:318:24: 318:25 note: `s` moved here because it has type `Square`, which is non-copyable -enums.rs:318 promote_to_queen_2(s); - ^ -``` +The previous section described a tree datatype, and showed a program +that computed the sum of the integers in a tree instance. -The error message is telling us exactly what happened: the argument to -`promote_to_queen_2` is moved when the function is called; thus the -attempt to reference `s` in the `assert_eq!` invocation fails, because -`s` has been moved. +That version of `tree_weight` has one big downside, however: it takes +its input tree by value. Once you pass a tree to `tree_weight_v1`, that +tree is gone (as in, deallocated). -(This illustrates why one might *not* add `derive(Copy)` to every data -type where it would otherwise be legal; leaving out `derive(Copy)` can -catch certain bugs.) +```rust,code +#[test] +fn tree_demo_v1_fails() { + let tree = sample_tree(); + assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5); -### Try, try again; taking a reference + // If you uncomment this line below ... + + // assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5); -So, here's a third try, where we take a reference to the `Square`. + // ... you will get: error: use of moved value: `tree` +} +``` + +This is *not* a consequence, however, of using `match`; it is rather +a consequence of the function signature that was chosen: ```rust -#[cfg(promote_attempt_3)] -fn promote_to_queen_3(s: &mut Square) { - match s { - &mut Square::Empty => {} - &mut Square::Occupied(Piece::White(mut shape)) | - &mut Square::Occupied(Piece::Black(mut shape)) => { - shape = Queen +fn tree_weight_v1(t: BinaryTree) -> i32 { 0 } +// ^~~~~~~~~~ this means this function takes ownership of `t` +``` + +In fact, in Rust, `match` is designed to work quite well *without* +taking ownership. In particular, the input to `match` is an L-value; +this means that the input expression is evaluated to a *memory +location*, and then match works by inspecting the data at that +location. + +(If the input expression is a variable name or a field/pointer +dereference, then the L-value is just the location of that variable or +field/memory. If the input expression is a function call or other +operation that generates an unnamed temporary value, then it will be +conceptually stored in a temporary area, and that is the memory +location that `match` will inspect.) + +So, if we want a version of `tree_weight` that merely borrows a tree +rather than taking ownership of it, then we will need to make use of +this feature of Rust's `match`. + +```rust,code +/// Sum of values in all the nodes and leaves of `t`. +fn tree_weight_v2(t: &BinaryTree) -> i32 { + // ^~~~~~~~~~~ The `&` means we are *borrowing* the tree + match *t { + BinaryTree::Leaf(payload) => payload, + BinaryTree::Node(ref left, payload, ref right) => { + tree_weight_v2(left) + payload + tree_weight_v2(right) } } } -#[cfg(promote_attempt_3)] #[test] -fn demo_promote_3() { - let mut p = Square::Occupied(Piece::White(Pawn)); - promote_to_queen_3(&mut p); - assert_eq!(p, Square::Occupied(Piece::White(Queen))); +fn tree_demo_2() { + let tree = sample_tree(); + assert_eq!(tree_weight_v2(&tree), (1 + 2 + 3) + 4 + 5); } ``` -We again see the warning: - -``` -enums.rs:355:44: 355:49 warning: variable `shape` is assigned to, but never used, #[warn(unused_variables)] on by default -enums.rs:355 &mut Square::Occupied(Piece::White(mut shape)) | - ^~~~~~~~~ -enums.rs:357:13: 357:14 warning: value assigned to `shape` is never read, #[warn(unused_assignments)] on by default -enums.rs:357 shape = Queen - ^~~~~ -``` - -This warning is again warranted, as the test fails: - -``` -test demo_promote_3 ... FAILED - -failures: - ----- demo_promote_3 stdout ---- -thread 'demo_promote_3' panicked at 'assertion failed: `(left == right)` (left: `Occupied(White(Pawn))`, right: `Occupied(White(Queen))`)', enums.rs:367 -``` - -### Keeping `ref`s into referenced data - -So, what happened here? - -The answer is: Even though we have ensured that `Square` is not -accidentally copied, there is nothing stopping the *contents* of -`Square` from being copied. So in a `match` arm like -``` -&mut Square::Occupied(Piece::Black(mut shape)) => { ... } -``` -if the discriminant value matches that arm, then it will put a -copy of its shape into `shape`. - -This brings us to a very important point about how `match` works in -Rust: it matches its inputs in-place, but normal bindings like the -`mut shape` above will move (or copy) the matched substructure into -fresh locations. - -If you want to capture a reference into the matched substructure, -either to avoid extraneous copying, or to enable modification of the -original input value, then you need to use a `ref`-pattern. - -With this knowledge in hand, let us try again. - -In addition, our fourth try simplifies the code slightly by -dereferencing the argument `*s`. - -```rust -fn promote_to_queen_4(s: &mut Square) { - match *s { - Square::Empty => {} - Square::Occupied(Piece::White(ref mut shape)) | - Square::Occupied(Piece::Black(ref mut shape)) => { - *shape = Queen +The function `tree_weight_v2` looks very much like `tree_weight_v1`. +The only differences are: we take `t` as a borrowed reference (the `&` +in its type), and, importantly, we use `ref`-bindings for `left` and +`right` in the `Node` case. + +The `ref`-binding is a crucial part of how destructuring bind of +L-values works. + +When matching a value of type `T`, an identifier pattern `I` will, on +a successful match, *move* the value out of the original input and +into `I`. Thus we can always conclude in such a case that `I` has type +`T`, or "`I: T`". (For some types `T`, known as *copyable* `T` or "`T` +implements `Copy`", the value will in fact be copied into `I` for such +identifier patterns; but in general types are not copyable; either +way, such bindings do mean that `I` has ownership of a value of type +`T`.) + +Thus, the bindings of `payload` in `tree_weight_v2` both have type +`i32`; the `i32` type implements `Copy`, so the weight is copied into +`payload` in both arms. + +However, when matching a value of type `T`, a `ref`-pattern `ref I` +will, on a successful match, merely *borrow* a reference into the +matched data. In other words, a successful `ref I` match of a value of +type `T` will imply that `I: &T`. Thus, in the `Node` arm of +`tree_weight_v2`, `left` will be reference the left-hand box (which +holds a tree), and `right` will reference the right-hand box (which +also holds a tree). Then we can pass those borrowed references to +trees into the recursive calls to `tree_weight_v2`. + +Likewise, a `ref mut`-pattern (`ref mut I`) will, on a successful +match, take a borrow a *mutable reference* `&mut T`, (which allows +mutation and ensures there are no other active references to that data +at the same time). An important detail here is the destructuring +binding forms like `match` allows one to take mutable references to +disjoint parts of the data simultaneously. + +```rust,code +/// Increment the values in all the nodes and leaves of `t`. +fn tree_grow(t: &mut BinaryTree) { + // ^~~~~~~~~~~~~~~ `&mut`: we have unaliased access to the tree + match *t { + BinaryTree::Leaf(ref mut payload) => *payload += 1, + BinaryTree::Node(ref mut left, ref mut payload, ref mut right) => { + tree_grow(left); + *payload += 1; + tree_grow(right); } } } #[test] -fn demo_promote_4() { - let mut p = Square::Occupied(Piece::White(Pawn)); - promote_to_queen_4(&mut p); - assert_eq!(p, Square::Occupied(Piece::White(Queen))); +fn tree_demo_3() { + let mut tree = sample_tree(); + tree_grow(&mut tree); + assert_eq!(tree_weight_v2(&tree), (2 + 3 + 4) + 5 + 6); } ``` -Compiling and running our code now yields: - -``` -running 7 tests -test demo_debug_format ... ok -test demo_one_letter_collect ... ok -test demo_one_letter ... ok -test demo_debug_format_2 ... ok -test demo_promote_4 ... ok -test check_renders ... ok -test demo_promote_functional ... ok - -test result: ok. 7 passed; 0 failed; 0 ignored; 0 measured -``` - -Huzzah, it works! - -The dereference `*s` works because `match` works on both "L-value" and -"R-value" expressions; L-value expressions evaluate to memory -locations, while R-value expressions evaluate to values that are then -stored, if necessary, in temporary memory locations. It simplified our -code because allowed us to sidestep writing `&mut` at the beginning of -each of our patterns, which was not such a great burden for this tiny -code snippet, but can be much more annoying when working with `match` -expressions that have many more arms, amplifying the redundancy. - -## Avoiding unsoundness +### Avoiding unsoundness (This section is adapted from the Rust demo we presented at the 2014 ML workshop.) @@ -579,7 +527,7 @@ overwrite state secretly, subverting the type-system? Consider the following code: -```rust +```rust,code #[test] fn sound_code() { enum E { A(fn (i8) -> i8), B(usize) } @@ -625,7 +573,7 @@ location and try to interpret it as executable code. But watch: -```rust +```rust,code #[cfg(wont_compile)] #[test] fn unsound_code_1() { @@ -653,8 +601,9 @@ fn unsound_code_1() { } ``` -As you might have inferred from the `cfg` annotation above, this -will not compile. Attempting to compile it yields: +This will not compile. (The `cfg` annotation above actually stops the +compiler from attempting to compile it.) Removing the `cfg` line and +attempting to compile it yields: ``` enums.rs:569:30: 569:51 error: cannot assign to `*p1` because it is borrowed @@ -679,7 +628,7 @@ compiling are not performing a local check of just the single function non-local attempts to subvert the type system by sneaking the overwrite past the static checks are foiled, as shown here: -```rust +```rust,code #[cfg(wont_compile)] #[test] fn unsound_code_2() { @@ -730,11 +679,11 @@ This illustrates why Rust takes such pains to support affine typing of ## Conclusion -Thus ends our tour of enums in Rust. For more information on details -that were not covered here, such as binding via `ident @ pattern`, or -the potentially subtle difference between `{ let id = expr; ... }` -versus `match expr { id => { ... } }`, consult the Rust documentation, -or quiz our awesome community (in `#rust` on IRC, or in the -[user group]). +Thus ends our tour of `match` and enums in Rust. For more information +on details that were not covered here, such as binding via `ident @ +pattern`, or the potentially subtle difference between `{ let id = +expr; ... }` versus `match expr { id => { ... } }`, consult the Rust +documentation, or quiz our awesome community (in `#rust` on IRC, or in +the [user group]). [user group]: http://users.rust-lang.org/ From 13137825f010be16094b4f0c9726b6e057e92483 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:07:24 +0200 Subject: [PATCH 080/386] Try to add some emphasis that pattern matching ergonomics are crucial. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 318d36754..5175db1e4 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -31,9 +31,9 @@ together are: * `match` embraces both imperative and applicative styles of programming. The compiler's static analyses work hard to ensure - statement-oriented programming remains palatable, leaving the - question of whether expression-orientation is better to style - guides. + statement-oriented programming remains palatable. At the same + time, the `match` construct enables ergonomic case analysis far + beyond what is provided by a C or Java style `switch` statement. * Destructuring bind of *L-values*: Rust encourages the developer to think carefully about ownership and borrowing. To ensure that From 6f46621963985840f33e7ea08dd7437fe02c0062 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:08:21 +0200 Subject: [PATCH 081/386] replace my `rust,code` annotations with `rust`, to get proper highlighting. --- ...15-04-17-Enums-match-mutation-and-moves.md | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 5175db1e4..2cd527556 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -76,7 +76,7 @@ executable; you can cut-and-paste the code snippets into a file `demo.rs`, compile the file with `--test`, and run the resulting binary to see the tests run.) -```rust,code +```rust enum Answer { Higher, Lower, @@ -115,7 +115,7 @@ or that pattern, et cetera. These features are illustrated in the following revision to the guessing-game answer generation strategy: -```rust,code +```rust struct GuessState { guess: u32, answer: Answer, @@ -190,7 +190,7 @@ exposes logical errors. that such expressions always evaluates to a value of the correct type (or jump elsehwere in the program, as illustrated here): -```rust,code +```rust fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { let next_guess = match answer { Answer::Higher => prior_guess + 10, @@ -224,7 +224,7 @@ it is written in a style similar to a `switch` in a statement-oriented language like C (or C++, Java, et cetera), where the arms of the `match` are executed for their side-effect alone: -```rust,code +```rust fn num_to_ordinal(x: u32) -> String { let suffix; match (x % 10, x % 100) { @@ -273,7 +273,7 @@ An important case where this arises is when one wants to initialize some state and then borrow from it, but only on *some* control-flow branches. -```rust,code +```rust fn sometimes_initialize(input: i32) { let string; let borrowed; @@ -325,7 +325,7 @@ For example, a binary tree is either a leaf, or an internal node with references to two child trees. Here is one way to encode a tree of integers in Rust: -```rust,code +```rust enum BinaryTree { Leaf(i32), Node(Box, i32, Box) @@ -349,7 +349,7 @@ az a `Node`, but the compiler statically ensure such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. -```rust,code +```rust /// Sum of values in all the nodes and leaves of `t`. fn tree_weight_v1(t: BinaryTree) -> i32 { match t { @@ -397,7 +397,7 @@ That version of `tree_weight` has one big downside, however: it takes its input tree by value. Once you pass a tree to `tree_weight_v1`, that tree is gone (as in, deallocated). -```rust,code +```rust #[test] fn tree_demo_v1_fails() { let tree = sample_tree(); @@ -436,7 +436,7 @@ So, if we want a version of `tree_weight` that merely borrows a tree rather than taking ownership of it, then we will need to make use of this feature of Rust's `match`. -```rust,code +```rust /// Sum of values in all the nodes and leaves of `t`. fn tree_weight_v2(t: &BinaryTree) -> i32 { // ^~~~~~~~~~~ The `&` means we are *borrowing* the tree @@ -492,7 +492,7 @@ at the same time). An important detail here is the destructuring binding forms like `match` allows one to take mutable references to disjoint parts of the data simultaneously. -```rust,code +```rust /// Increment the values in all the nodes and leaves of `t`. fn tree_grow(t: &mut BinaryTree) { // ^~~~~~~~~~~~~~~ `&mut`: we have unaliased access to the tree @@ -527,7 +527,7 @@ overwrite state secretly, subverting the type-system? Consider the following code: -```rust,code +```rust #[test] fn sound_code() { enum E { A(fn (i8) -> i8), B(usize) } @@ -573,7 +573,7 @@ location and try to interpret it as executable code. But watch: -```rust,code +```rust #[cfg(wont_compile)] #[test] fn unsound_code_1() { @@ -628,7 +628,7 @@ compiling are not performing a local check of just the single function non-local attempts to subvert the type system by sneaking the overwrite past the static checks are foiled, as shown here: -```rust,code +```rust #[cfg(wont_compile)] #[test] fn unsound_code_2() { From 9c49d335161808e4d39b0f5f470ee9a82461fe1f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:15:12 +0200 Subject: [PATCH 082/386] try to improve phrasing of one point about anti-patterns. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 2cd527556..4eb6a9c3e 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -311,9 +311,11 @@ generated code ensures that at the end of the scope of `string`, its data is deallocated if it was previously initialized.) In short, for soundness, the Rust language ensures that data is always -initialized before it is referenced, but the designers have attempted -to not require artifices like dummy-initializations inserted solely to -placate such requirements. +initialized before it is referenced, but the designers have strived to +avoid requiring artifical coding patterns inserted solely to placate +Rust's static analyses (such as requiring one to initialize `string` +above with some dummy data just so that it can be borrowed later). + ### Algebraic Data Types and Data Invariants From df55592b883c67cb114a32fd7a0cd644a243c78b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:19:18 +0200 Subject: [PATCH 083/386] Attempt to further emphasize ergonomics in the lead bullets. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 4eb6a9c3e..93d9d628e 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -26,14 +26,17 @@ In this post we explore how Rust processes such data via `match`. The crucial elements that `match` and its counterpart `enum` tie together are: +* Structural pattern matching of algebraic data types: The `match` + construct enables case analysis with ergonomics that are vastly + improved over that provided by a C or Java style `switch` statement. + * Exhaustive case analysis, which ensures that no case is omitted when processing an input. * `match` embraces both imperative and applicative styles of - programming. The compiler's static analyses work hard to ensure - statement-oriented programming remains palatable. At the same - time, the `match` construct enables ergonomic case analysis far - beyond what is provided by a C or Java style `switch` statement. + programming: The compiler's static analyses work hard to ensure + statement-oriented programming remains palatable, rather than + forcing everyone to adopt an expression-oriented mindset. * Destructuring bind of *L-values*: Rust encourages the developer to think carefully about ownership and borrowing. To ensure that From e8acc0641c08853b3d2dfefec56d00398ad9255b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:22:28 +0200 Subject: [PATCH 084/386] Try to clarify L-value terminology when first introduced. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 93d9d628e..e9271c5fc 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -425,10 +425,11 @@ fn tree_weight_v1(t: BinaryTree) -> i32 { 0 } ``` In fact, in Rust, `match` is designed to work quite well *without* -taking ownership. In particular, the input to `match` is an L-value; -this means that the input expression is evaluated to a *memory -location*, and then match works by inspecting the data at that -location. +taking ownership. In particular, the input to `match` is an *L-value +expression*; this means that the input expression is evaluated to a +*memory location* where the value lives (as opposed to an R-value +expression, which conceptually evaluates to the value itself). Then +`match` works by inspecting the data at that location. (If the input expression is a variable name or a field/pointer dereference, then the L-value is just the location of that variable or From 2d208b5b552102d51ea1089a428c58084db5e481 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:26:32 +0200 Subject: [PATCH 085/386] introduce and explain the `tree_grow` example a bit better. --- ...15-04-17-Enums-match-mutation-and-moves.md | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index e9271c5fc..559d0ee80 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -498,16 +498,19 @@ at the same time). An important detail here is the destructuring binding forms like `match` allows one to take mutable references to disjoint parts of the data simultaneously. +This code demonstrates this concept by incrementing all of the +values in a given tree. + ```rust /// Increment the values in all the nodes and leaves of `t`. fn tree_grow(t: &mut BinaryTree) { // ^~~~~~~~~~~~~~~ `&mut`: we have unaliased access to the tree - match *t { + match *t { BinaryTree::Leaf(ref mut payload) => *payload += 1, BinaryTree::Node(ref mut left, ref mut payload, ref mut right) => { tree_grow(left); - *payload += 1; - tree_grow(right); + *payload += 1; + tree_grow(right); } } } @@ -515,11 +518,21 @@ fn tree_grow(t: &mut BinaryTree) { #[test] fn tree_demo_3() { let mut tree = sample_tree(); - tree_grow(&mut tree); + tree_grow(&mut tree); assert_eq!(tree_weight_v2(&tree), (2 + 3 + 4) + 5 + 6); } ``` +Note that the code above now binds `payload` by a `ref mut`-pattern; +if it did not use a `ref` pattern, then payload would be bound to a +local copy of the integer, while we want to modify the actual integer +*in the tree itself*. Thus we need a reference to that integer. + +Note also that the code is able to bind `left` and `right` +simultaneously in the `Node` arm. The compiler knows that the two +values cannot alias, and thus it allows both `&mut`-references to live +simultaneously. + ### Avoiding unsoundness (This section is adapted from the Rust demo we presented at the 2014 From b1f261101300a9cfe8ff15e9d2c43b9e218bd81f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:30:06 +0200 Subject: [PATCH 086/386] Removed the "Avoiding unsoundness" section. --- ...15-04-17-Enums-match-mutation-and-moves.md | 163 ------------------ 1 file changed, 163 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 559d0ee80..0374c9c2f 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -533,169 +533,6 @@ simultaneously in the `Node` arm. The compiler knows that the two values cannot alias, and thus it allows both `&mut`-references to live simultaneously. -### Avoiding unsoundness - -(This section is adapted from the Rust demo we presented at the 2014 -ML workshop.) - -A potentially non-obvious issue arises when a supposedly-sound -language adds support for `ref mut`, or even just `ref`, in a -non-moving/non-copying `match` expression: How does one prevent -someone from injecting unsound behavior by using mutable references to -overwrite state secretly, subverting the type-system? - -Consider the following code: - -```rust -#[test] -fn sound_code() { - enum E { A(fn (i8) -> i8), B(usize) } - fn add3(x:i8) -> i8 { x + 3 } - let mut a = E::A(add3); let mut b = E::B(19); - { - let m1 = &mut a; let m2 = &mut b; - foo(m1, m2); - } - match b { - E::A(_fn) => println!("b is an E::A"), - E::B(val) => println!("b is an E::B: 0x{:x}", val), - } - - fn foo(p1: &mut E, p2: &mut E) { - match p1 { - &mut E::B(..) => panic!("cannot happen"), - &mut E::A(ref adder) => { - /* WATCH: */ *p2 = E::B(0xBadC0de); - println!("{}", (*adder)(14)); - } - } - } -} -``` - -The above compiles and runs just fine: the references to `a` and `b` -are copied to `p1` and `p2` respectively for the call to `foo`, `b` is -imperatively updated via `p2`, `foo` prints out `17` (= 14 + 3), and -then after `foo` returns it prints out `b is an E::B: 0xbadc0de`. - -The question is: what happens when we tweak the test slightly? - -### Attempted subversion via local overwrites - -For example, what if we imperatively modify `*p1` instead of `*p2`, -but leave the code otherwise unchanged? - -Storing the `E::B(0xBadCode)` would invalidate the data held in -`adder` (indeed, it would put "bad code" there), and so the subsequent -invocation of `adder` will jump to some (potentially invalid) memory -location and try to interpret it as executable code. - -But watch: - -```rust -#[cfg(wont_compile)] -#[test] -fn unsound_code_1() { - enum E { A(fn (i8) -> i8), B(usize) } - fn add3(x:i8) -> i8 { x + 3 } - let mut a = E::A(add3); let mut b = E::B(19); - { - let m1 = &mut a; let m2 = &mut b; - foo(m1, m2); - } - match b { - E::A(_fn) => println!("b is an E::A"), - E::B(val) => println!("b is an E::B: 0x{:x}", val), - } - - fn foo(p1: &mut E, p2: &mut E) { - match p1 { - &mut E::B(..) => panic!("cannot happen"), - &mut E::A(ref adder) => { - /* was p2 */ *p1 = E::B(0xBadC0de); - println!("{}", (*adder)(14)); - } - } - } -} -``` - -This will not compile. (The `cfg` annotation above actually stops the -compiler from attempting to compile it.) Removing the `cfg` line and -attempting to compile it yields: - -``` -enums.rs:569:30: 569:51 error: cannot assign to `*p1` because it is borrowed -enums.rs:569 /* was p2 */ *p1 = E::B(0xBadC0de); - ^~~~~~~~~~~~~~~~~~~~~ -enums.rs:568:23: 568:32 note: borrow of `*p1` occurs here -enums.rs:568 &mut E::A(ref adder) => { - ^~~~~~~~~ -``` - -So, the compiler prevents us from overwriting the function pointer -with bogus data! (Of course, if you *really* want to shoot yourself in -the foot, you can resort to `unsafe` code to sneak the overwrite -through; at that point you are explicitly side-stepping the type -system, which Rust allows.) - -### Attempted subversion via aliasing - -Furthermore, the same rules that prevented the last example from -compiling are not performing a local check of just the single function -`foo`; they are enforcing a *global* soundness property. Other -non-local attempts to subvert the type system by sneaking the -overwrite past the static checks are foiled, as shown here: - -```rust -#[cfg(wont_compile)] -#[test] -fn unsound_code_2() { - enum E { A(fn (i8) -> i8), B(usize) } - fn add3(x:i8) -> i8 { x + 3 } - let mut a = E::A(add3); let mut b = E::B(19); - { - let m1 = &mut a; let m2 = &mut b; - foo(m1, m1); - } - match b { - E::A(_fn) => println!("b is an E::A"), - E::B(val) => println!("b is an E::B: 0x{:x}", val), - } - - fn foo(p1: &mut E, p2: &mut E) { - match p1 { - &mut E::B(..) => panic!("cannot happen"), - &mut E::A(ref adder) => { - /* watch? */ *p2 = E::B(0xBadC0de); - println!("{}", (*adder)(14)); - } - } - } -} -``` - -The above is attempting to create an *alias* between `p1` and `p2`, -thus causing the write to `p2` to actually overwrite the data -we matched in `p1`. - -However, this example also fails to compile: - -``` -enums.rs:612:17: 612:19 error: cannot borrow `*m1` as mutable more than once at a time -enums.rs:612 foo(m1, m1); - ^~ -enums.rs:612:13: 612:15 note: previous borrow of `*m1` occurs here; the mutable borrow prevents subsequent moves, borrows, or modification of `*m1` until the borrow ends -enums.rs:612 foo(m1, m1); - ^~ -enums.rs:612:20: 612:20 note: previous borrow ends here -enums.rs:612 foo(m1, m1); - ^ -``` - -This illustrates why Rust takes such pains to support affine typing of -`&mut T` and other owned types: It is necessary for type soundness! - ## Conclusion Thus ends our tour of `match` and enums in Rust. For more information From 7db2de3c6f2d98dee0ff4e98cfe29fd375785527 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:32:41 +0200 Subject: [PATCH 087/386] fix typo --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 0374c9c2f..6a5fc8366 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -191,7 +191,7 @@ exposes logical errors. * Second, since `match` is an expression form, exhaustiveness ensures that such expressions always evaluates to a value of the correct type -(or jump elsehwere in the program, as illustrated here): +(or jump elsewhere in the program, as illustrated here): ```rust fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { From 656df8648079c8b66f72ae43641bac1c1f9be737 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:34:45 +0200 Subject: [PATCH 088/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6a5fc8366..c1b80a4d5 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -350,7 +350,7 @@ encounter a `BinaryTree::Node` that does not have a left-hand child. There is no need to check for null. One *does* need to check whether a given `BinaryTree` is a `Leaf` or -az a `Node`, but the compiler statically ensure such checks are done: +as a `Node`, but the compiler statically ensure such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. From 1686f8f3754b58e191b7a94d8da2cd5f43e281ec Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:35:13 +0200 Subject: [PATCH 089/386] fix the fix for the previous typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index c1b80a4d5..8caea18fe 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -350,7 +350,7 @@ encounter a `BinaryTree::Node` that does not have a left-hand child. There is no need to check for null. One *does* need to check whether a given `BinaryTree` is a `Leaf` or -as a `Node`, but the compiler statically ensure such checks are done: +is a `Node`, but the compiler statically ensure such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. From 8b74b75d49eb88bd8d8ad248d136ba33b7b12460 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:37:01 +0200 Subject: [PATCH 090/386] formatting improvement: use lowercase `i` for the hypothetical ident patterns. --- ...015-04-17-Enums-match-mutation-and-moves.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 8caea18fe..9693bdb01 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -469,29 +469,29 @@ in its type), and, importantly, we use `ref`-bindings for `left` and The `ref`-binding is a crucial part of how destructuring bind of L-values works. -When matching a value of type `T`, an identifier pattern `I` will, on +When matching a value of type `T`, an identifier pattern `i` will, on a successful match, *move* the value out of the original input and -into `I`. Thus we can always conclude in such a case that `I` has type -`T`, or "`I: T`". (For some types `T`, known as *copyable* `T` or "`T` -implements `Copy`", the value will in fact be copied into `I` for such +into `i`. Thus we can always conclude in such a case that `i` has type +`T`, or "`i: T`". (For some types `T`, known as *copyable* `T` or "`T` +implements `Copy`", the value will in fact be copied into `i` for such identifier patterns; but in general types are not copyable; either -way, such bindings do mean that `I` has ownership of a value of type +way, such bindings do mean that `i` has ownership of a value of type `T`.) Thus, the bindings of `payload` in `tree_weight_v2` both have type `i32`; the `i32` type implements `Copy`, so the weight is copied into `payload` in both arms. -However, when matching a value of type `T`, a `ref`-pattern `ref I` +However, when matching a value of type `T`, a `ref`-pattern `ref i` will, on a successful match, merely *borrow* a reference into the -matched data. In other words, a successful `ref I` match of a value of -type `T` will imply that `I: &T`. Thus, in the `Node` arm of +matched data. In other words, a successful `ref i` match of a value of +type `T` will imply that `i: &T`. Thus, in the `Node` arm of `tree_weight_v2`, `left` will be reference the left-hand box (which holds a tree), and `right` will reference the right-hand box (which also holds a tree). Then we can pass those borrowed references to trees into the recursive calls to `tree_weight_v2`. -Likewise, a `ref mut`-pattern (`ref mut I`) will, on a successful +Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful match, take a borrow a *mutable reference* `&mut T`, (which allows mutation and ensures there are no other active references to that data at the same time). An important detail here is the destructuring From fe0d990b4e91ff9241a3f873ba6cf4a3328c4aac Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Thu, 16 Apr 2015 19:38:50 +0200 Subject: [PATCH 091/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 9693bdb01..bc3c990b1 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -492,7 +492,7 @@ also holds a tree). Then we can pass those borrowed references to trees into the recursive calls to `tree_weight_v2`. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful -match, take a borrow a *mutable reference* `&mut T`, (which allows +match, borrow a *mutable reference* `&mut T` into the input, (which allows mutation and ensures there are no other active references to that data at the same time). An important detail here is the destructuring binding forms like `match` allows one to take mutable references to From 81f79814ad981f7cc63d31a1cc48c41f04524131 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 01:32:04 +0200 Subject: [PATCH 092/386] incorporated review feedback. --- ...15-04-17-Enums-match-mutation-and-moves.md | 278 +++++++++++------- 1 file changed, 172 insertions(+), 106 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index bc3c990b1..1085078ca 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -33,7 +33,7 @@ together are: * Exhaustive case analysis, which ensures that no case is omitted when processing an input. -* `match` embraces both imperative and applicative styles of +* `match` embraces both imperative and functional styles of programming: The compiler's static analyses work hard to ensure statement-oriented programming remains palatable, rather than forcing everyone to adopt an expression-oriented mindset. @@ -104,7 +104,7 @@ fn demo_suggest_guess() { Patterns can also match structured data (e.g. tuples, slices, user-defined data types) via corresponding patterns. In such patterns, one often -binds substructure of the input to local variables (identifer patterns), +binds substructure of the input to local variables (identifier patterns), for use either in the arm's predicate or in its result. The special `_` pattern matches any single value, and is often used as @@ -132,7 +132,7 @@ fn suggest_guess_smarter(s: GuessState) { println!("we won with {}!", p); } GuessState { answer: Answer::Higher, guess: l, low: _, high: h } | - GuessState { answer: Answer::Lower, guess: h, low: l, high: _ } => { + GuessState { answer: Answer::Lower, guess: h, low: l, high: _ } => { let mid = l + ((h - l) / 2); println!("lets try {} next", mid); } @@ -147,6 +147,10 @@ fn demo_guess_state() { } ``` +This ability to simultaneously perform case analysis *and* bind input +substructure leads to powerful, clear, and concise code, focusing the +reader's attention directly on the data relevant to the case at hand. + That is `match` in a nutshell. So, what is the interplay between this construct and Rust's approach to @@ -154,8 +158,12 @@ ownership and safety in general? ### Exhaustive case analysis -One important method of analytical thinking is case analysis: Dividing -a problem into some number of separate cases, and then analyzing each +`match` enforces exhaustive case analysis, which helps catch bugs in +program logic and ensures that the value of a match expression is +well-defined. + +Case analysis is an important problem solving technique: Dividing a +problem into some number of separate cases, and then analyzing each case individually. For this method of problem solving to work, the cases must be @@ -164,7 +172,9 @@ would mean a potential problem instance for which no solution has been identified. This brings us to one of the fundamental restrictions of Rust's -`match` construct: the collection of provided cases must be exhautive. +`match` construct: the collection of cases must be exhaustive. In +other words, every possible input value must be covered by the pattern +for a least one arm in the match. So, for example, the following code is rejected at compile-time. @@ -199,7 +209,7 @@ fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { Answer::Higher => prior_guess + 10, Answer::Lower => prior_guess - 1, Answer::Bingo => { - println!("we won!"); + println!("we won with {}!", prior_guess); return; } }; @@ -214,11 +224,94 @@ fn demo_guess_fixed() { } ``` +### Algebraic Data Types and Data Invariants + +Algebraic data types succinctly describe classes of data and allow one +to encode rich structural invariants. + +An `enum` type allows one to define mutually-exclusive classes of +values. The examples shown above used `enum` for simple symbolic tags, +but in Rust, such definitions can define much richer classes of data. + +For example, a binary tree is either a leaf, or an internal node with +references to two child trees. Here is one way to encode a tree of +integers in Rust: + +```rust +enum BinaryTree { + Leaf(i32), + Node(Box, i32, Box) +} +``` + +(The `Box` type describes an owning reference to a heap-allocated +instance of `V`; if you own a `Box`, then you also own the `V` it +contains, and can mutate it, lend out references to it, et cetera, and +when you finish with the box and let it fall out of scope, it will +automatically clean up the resources associated with the +heap-allocated `V`.) + +The above definition ensures that if we are given a `BinaryTree`, it +will always fall into one of the above two cases. One will never +encounter a `BinaryTree::Node` that does not have a left-hand child. +There is no need to check for null. + +One *does* need to check whether a given `BinaryTree` is a `Leaf` or +is a `Node`, but the compiler statically ensure such checks are done: +you cannot accidentally interpret the data of a `Leaf` as if it were a +`Node`, nor vice versa. + +```rust +/// Sum of values in all the nodes and leaves of `t`. +fn tree_weight_v1(t: BinaryTree) -> i32 { + match t { + BinaryTree::Leaf(payload) => payload, + BinaryTree::Node(left, payload, right) => { + tree_weight_v1(*left) + payload + tree_weight_v1(*right) + } + } +} + +/// Looks like: +/// +/// (4) +/// | +/// +--(2) +/// | | +/// | +--[1] +/// | | +/// | +--[3] +/// | +/// +--[5] +/// +fn sample_tree() -> BinaryTree { + let l1 = Box::new(BinaryTree::Leaf(1)); + let l3 = Box::new(BinaryTree::Leaf(3)); + let n2 = Box::new(BinaryTree::Node(l1, 2, l3)); + let l5 = Box::new(BinaryTree::Leaf(5)); + + BinaryTree::Node(n2, 4, l5) +} + +#[test] +fn tree_demo_1() { + let tree = sample_tree(); + assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5); +} +``` + ### Both expression- and statement-oriented Unlike many languages that offer pattern matching, Rust *embraces* both statement- and expression-oriented programming. +Many functional languages that offer pattern matching encourage one to +write in an "expression-oriented style", where the focus is always on +the value returned by combining expressions and evaluating them, and +side-effects are discouraged. This style contrasts with imperative +languages, which encourage a statement-oriented style that focuses on +sequences of commands executed solely for their side-effects. + Consider writing a function which maps a non-negative integer to a string rendering it as an ordinal ("1st", "2nd", "3rd", ...). @@ -267,10 +360,27 @@ we could assign `suffix` multiple times, the compiler would force us to mark `suffix` as mutable). To be clear, the above program certainly *can* be written in an -expression-oriented style. The point is that each of the styles has -its use cases, and switching to a statement-oriented style does not -sacrifice every other feature that Rust provides, such as ensuring -that a non-`mut` binding is assigned at most once. +expression-oriented style in Rust; for example, like so: + +```rust +fn num_to_ordinal_expr(x: u32) -> String { + format!("{}{}", x, match (x % 10, x % 100) { + (1, 1) | (1, 21...91) => "st", + (2, 2) | (2, 22...92) => "nd", + (3, 3) | (3, 23...93) => "rd", + _ => "th" + }) +} +``` + +Sometimes expression-oriented style can yield very succinct code; +other times the style requires contortions that can be more readily +side-stepped when writing in statement-oriented style. + +Each of the styles has its use cases. Crucially, switching to a +statement-oriented style in Rust does not sacrifice every other +feature that Rust provides, such as the guarantee that a non-`mut` +binding is assigned at most once. An important case where this arises is when one wants to initialize some state and then borrow from it, but only on @@ -278,129 +388,69 @@ initialize some state and then borrow from it, but only on ```rust fn sometimes_initialize(input: i32) { - let string; - let borrowed; + let string: String; // a dynamically-constructed string value + let borrowed: &str; // a reference to string data match input { 0...100 => { + // Construct a String on the fly... string = format!("input prints as {}", input); + // ... and then borrow from inside it. borrowed = &string[6..]; } _ => { + // String literals are *already* borrowed references borrowed = "expected between 0 and 100"; } } println!("borrowed: {}", borrowed); - // (Below would cause compile-time error if uncommented.) - // println!("string: {}", string); + // Below would cause compile-time error if uncommented... + + // println!("string: {}", string); + + // ...namely: error: use of possibly uninitialized variable: `string` } #[test] fn demo_sometimes_initialize() { - sometimes_initialize(23); - sometimes_initialize(123); + sometimes_initialize(23); // this invocation will initialize `string` + sometimes_initialize(123); // this one will not } ``` The interesting thing about the above code is that after the `match`, we are not allowed to directly access `string`, because the compiler requires that the variable be initialized on every path through the -program. At the same time, we *can* access the data that is held -*within* `string`, because a reference to that data is held by the -`borrowed` variable, which we ensure is initialized on every program -path. (The compiler ensures that no outstanding borrows of the +program. At the same time, we *can*, via `borrowed`, access the data that +is held *within* `string`, because a reference to that data is held by the +`borrowed` variable when we go through the first match arm, and we +ensure `borrowed` itself is initialized on every execution path +through the program that reaches the `println!` that uses `borrowed`. + +(The compiler ensures that no outstanding borrows of the `string` data could possible outlive `string` itself, and the generated code ensures that at the end of the scope of `string`, its data is deallocated if it was previously initialized.) In short, for soundness, the Rust language ensures that data is always initialized before it is referenced, but the designers have strived to -avoid requiring artifical coding patterns inserted solely to placate +avoid requiring artificial coding patterns inserted solely to placate Rust's static analyses (such as requiring one to initialize `string` above with some dummy data just so that it can be borrowed later). - -### Algebraic Data Types and Data Invariants - -An `enum` type allows one to define mutually-exclusive classes of -values. The examples shown above used `enum` for simple symbolic tags, -but in Rust, such definitions can define much richer classes of data. - -For example, a binary tree is either a leaf, or an internal node with -references to two child trees. Here is one way to encode a tree of -integers in Rust: - -```rust -enum BinaryTree { - Leaf(i32), - Node(Box, i32, Box) -} -``` - -(The `Box` type describes an owning reference to a heap-allocated -instance of `V`; if you own a `Box`, then you also own the `V` it -contains, and can mutate it, lend out references to it, et cetera, and -when you finish with the box and let it fall out of scope, it will -automatically clean up the resources associated with the -heap-allocated `V`.) - -The above definition ensures that if we are given a `BinaryTree`, it -will always fall into one of the above two cases. One will never -encounter a `BinaryTree::Node` that does not have a left-hand child. -There is no need to check for null. - -One *does* need to check whether a given `BinaryTree` is a `Leaf` or -is a `Node`, but the compiler statically ensure such checks are done: -you cannot accidentally interpret the data of a `Leaf` as if it were a -`Node`, nor vice versa. - -```rust -/// Sum of values in all the nodes and leaves of `t`. -fn tree_weight_v1(t: BinaryTree) -> i32 { - match t { - BinaryTree::Leaf(payload) => payload, - BinaryTree::Node(left, payload, right) => { - tree_weight_v1(*left) + payload + tree_weight_v1(*right) - } - } -} - -/// Looks like: -/// -/// (4) -/// | -/// +--(2) -/// | | -/// | +--[1] -/// | | -/// | +--[3] -/// | -/// +--[5] -/// -fn sample_tree() -> BinaryTree { - let l1 = Box::new(BinaryTree::Leaf(1)); - let l3 = Box::new(BinaryTree::Leaf(3)); - let n2 = Box::new(BinaryTree::Node(l1, 2, l3)); - let l5 = Box::new(BinaryTree::Leaf(5)); - - BinaryTree::Node(n2, 4, l5) -} - -#[test] -fn tree_demo_1() { - let tree = sample_tree(); - assert_eq!(tree_weight_v1(tree), (1 + 2 + 3) + 4 + 5); -} -``` - ### Matching L-values -The previous section described a tree datatype, and showed a program -that computed the sum of the integers in a tree instance. +Matching an input can *borrow* input substructure, without taking +ownership; this is crucial for matching a reference (e.g. a value of +type `&T`). + +The "Algebraic Data Types" section above described a tree datatype, and +showed a program that computed the sum of the integers in a tree +instance. That version of `tree_weight` has one big downside, however: it takes its input tree by value. Once you pass a tree to `tree_weight_v1`, that -tree is gone (as in, deallocated). +tree is *gone* (as in, deallocated). ```rust #[test] @@ -427,9 +477,9 @@ fn tree_weight_v1(t: BinaryTree) -> i32 { 0 } In fact, in Rust, `match` is designed to work quite well *without* taking ownership. In particular, the input to `match` is an *L-value expression*; this means that the input expression is evaluated to a -*memory location* where the value lives (as opposed to an R-value -expression, which conceptually evaluates to the value itself). Then -`match` works by inspecting the data at that location. +*memory location* where the value lives. +`match` works by doing this evaluation and then +inspecting the data at that memory location. (If the input expression is a variable name or a field/pointer dereference, then the L-value is just the location of that variable or @@ -463,10 +513,19 @@ fn tree_demo_2() { The function `tree_weight_v2` looks very much like `tree_weight_v1`. The only differences are: we take `t` as a borrowed reference (the `&` -in its type), and, importantly, we use `ref`-bindings for `left` and +in its type), we added a dereference `*t`, and, +importantly, we use `ref`-bindings for `left` and `right` in the `Node` case. -The `ref`-binding is a crucial part of how destructuring bind of +The dereference `*t`, interpreted as an L-value expression, is just +extracting the memory address where the `BinaryTree` is represented +(since the `t: &BinaryTree` is just a *reference* to that data in +memory). The `*t` here is not making a copy of the tree, nor moving it +to a new temporary location, because `match` is treating it as an +L-value. + +The only piece left is the `ref`-binding, which +is a crucial part of how destructuring bind of L-values works. When matching a value of type `T`, an identifier pattern `i` will, on @@ -524,7 +583,7 @@ fn tree_demo_3() { ``` Note that the code above now binds `payload` by a `ref mut`-pattern; -if it did not use a `ref` pattern, then payload would be bound to a +if it did not use a `ref` pattern, then `payload` would be bound to a local copy of the integer, while we want to modify the actual integer *in the tree itself*. Thus we need a reference to that integer. @@ -535,7 +594,14 @@ simultaneously. ## Conclusion -Thus ends our tour of `match` and enums in Rust. For more information +Rust takes the ideas of algebraic data types and pattern matching +pioneered by the functional programming languages, and adapts them to +imperative programming styles and Rust's own ownership and borrowing +systems. The `enum` and `match` forms provide clean data definitions +and expressive power, while static analysis ensures that the resulting +programs are safe. + +For more information on details that were not covered here, such as binding via `ident @ pattern`, or the potentially subtle difference between `{ let id = expr; ... }` versus `match expr { id => { ... } }`, consult the Rust From e1aec240889dac6c09a430ca7b0d2836ef667d63 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 01:46:08 +0200 Subject: [PATCH 093/386] Added links to reference docs on `match` and `L-values`. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 1085078ca..5b70b17fd 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -475,7 +475,7 @@ fn tree_weight_v1(t: BinaryTree) -> i32 { 0 } ``` In fact, in Rust, `match` is designed to work quite well *without* -taking ownership. In particular, the input to `match` is an *L-value +taking ownership. In particular, the input to `match` is an *[L-value][L_value] expression*; this means that the input expression is evaluated to a *memory location* where the value lives. `match` works by doing this evaluation and then @@ -605,7 +605,9 @@ For more information on details that were not covered here, such as binding via `ident @ pattern`, or the potentially subtle difference between `{ let id = expr; ... }` versus `match expr { id => { ... } }`, consult the Rust -documentation, or quiz our awesome community (in `#rust` on IRC, or in +[documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). +[rust_docs]: https://doc.rust-lang.org/reference.html#match-expressions [user group]: http://users.rust-lang.org/ +[L_value]: https://doc.rust-lang.org/reference.html#lvalues,-rvalues-and-temporaries From 9fbbcad6640c7cb1fdaa7754c582937cd94a338b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 01:51:29 +0200 Subject: [PATCH 094/386] Improve wording. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 5b70b17fd..0977ede10 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -374,8 +374,8 @@ fn num_to_ordinal_expr(x: u32) -> String { ``` Sometimes expression-oriented style can yield very succinct code; -other times the style requires contortions that can be more readily -side-stepped when writing in statement-oriented style. +other times the style requires contortions that can be +avoided by writing in a statement-oriented style. Each of the styles has its use cases. Crucially, switching to a statement-oriented style in Rust does not sacrifice every other From b22c1edc5ca68dc18daff6f511cb3e01afdc7bf8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 11:44:09 +0200 Subject: [PATCH 095/386] Fix issues I noted during a morning review. --- ...015-04-17-Enums-match-mutation-and-moves.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 0977ede10..4b75838dd 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -261,8 +261,10 @@ is a `Node`, but the compiler statically ensure such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. +Here is a function that increments all of the integers in a tree +using `match`. + ```rust -/// Sum of values in all the nodes and leaves of `t`. fn tree_weight_v1(t: BinaryTree) -> i32 { match t { BinaryTree::Leaf(payload) => payload, @@ -421,14 +423,14 @@ fn demo_sometimes_initialize() { The interesting thing about the above code is that after the `match`, we are not allowed to directly access `string`, because the compiler requires that the variable be initialized on every path through the -program. At the same time, we *can*, via `borrowed`, access the data that -is held *within* `string`, because a reference to that data is held by the +program. At the same time, we *can*, via `borrowed`, access data that +may held *within* `string`, because a reference to that data is held by the `borrowed` variable when we go through the first match arm, and we ensure `borrowed` itself is initialized on every execution path through the program that reaches the `println!` that uses `borrowed`. (The compiler ensures that no outstanding borrows of the -`string` data could possible outlive `string` itself, and the +`string` data could possibly outlive `string` itself, and the generated code ensures that at the end of the scope of `string`, its data is deallocated if it was previously initialized.) @@ -493,7 +495,6 @@ rather than taking ownership of it, then we will need to make use of this feature of Rust's `match`. ```rust -/// Sum of values in all the nodes and leaves of `t`. fn tree_weight_v2(t: &BinaryTree) -> i32 { // ^~~~~~~~~~~ The `&` means we are *borrowing* the tree match *t { @@ -545,9 +546,9 @@ However, when matching a value of type `T`, a `ref`-pattern `ref i` will, on a successful match, merely *borrow* a reference into the matched data. In other words, a successful `ref i` match of a value of type `T` will imply that `i: &T`. Thus, in the `Node` arm of -`tree_weight_v2`, `left` will be reference the left-hand box (which -holds a tree), and `right` will reference the right-hand box (which -also holds a tree). Then we can pass those borrowed references to +`tree_weight_v2`, `left` will be a reference to the left-hand box (which +holds a tree), and `right` will likewise reference the right-hand tree. +Then we can pass those borrowed references to trees into the recursive calls to `tree_weight_v2`. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful @@ -561,7 +562,6 @@ This code demonstrates this concept by incrementing all of the values in a given tree. ```rust -/// Increment the values in all the nodes and leaves of `t`. fn tree_grow(t: &mut BinaryTree) { // ^~~~~~~~~~~~~~~ `&mut`: we have unaliased access to the tree match *t { From c9c3b847c1b6ec735d50846b77daac349a0df8fd Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 11:46:32 +0200 Subject: [PATCH 096/386] move parenthetical note about executing the demo code to after the first demo --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 4b75838dd..ce56f8b21 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -74,11 +74,6 @@ can also match user-defined symbolic data, defined via `enum`. The below code demonstrates generating the next guess (poorly) in a number guessing game, given the answer from a previous guess. -(Incidentally, nearly all the code in this post is directly -executable; you can cut-and-paste the code snippets into a file -`demo.rs`, compile the file with `--test`, and run the resulting -binary to see the tests run.) - ```rust enum Answer { Higher, @@ -102,6 +97,11 @@ fn demo_suggest_guess() { } ``` +(Incidentally, nearly all the code in this post is directly +executable; you can cut-and-paste the code snippets into a file +`demo.rs`, compile the file with `--test`, and run the resulting +binary to see the tests run.) + Patterns can also match structured data (e.g. tuples, slices, user-defined data types) via corresponding patterns. In such patterns, one often binds substructure of the input to local variables (identifier patterns), From 89608a309828576dceb705557cf227163840015b Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 11:48:53 +0200 Subject: [PATCH 097/386] improve suggest_guess_smarter presentation (invariant is low <= guess <= high, so have code reflect that) --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index ce56f8b21..31b0c422e 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -131,8 +131,8 @@ fn suggest_guess_smarter(s: GuessState) { GuessState { answer: Answer::Bingo, guess: p, .. } => { println!("we won with {}!", p); } - GuessState { answer: Answer::Higher, guess: l, low: _, high: h } | - GuessState { answer: Answer::Lower, guess: h, low: l, high: _ } => { + GuessState { answer: Answer::Higher, low: _, guess: l, high: h } | + GuessState { answer: Answer::Lower, low: l, guess: h, high: _ } => { let mid = l + ((h - l) / 2); println!("lets try {} next", mid); } From 91d85bb53eafab561eadd8749afa1febb497fea8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:14:55 +0200 Subject: [PATCH 098/386] Hopefully final edit. Inspired by aturon's note to put a summary sentence at the beginning of each subsection (which I did earlier), I tried also adding a very short summary sentence at the end of each section too. In some cases this led me to put in a bit more text just so the text flowed, e.g. going from a final example to the summary sentence. Also, along the way I found a few more ways to clarify the text. Finally, I could not resist adding a quick aside referencing modules and privacy; while I do think that Algebraic Data Types (ADTs) are important for encoding invariants, *Abstract Data Types (ADTs, heh) are if anything even more important for representation invariants, and so I wanted to ensure that I didn't pretend that what is presented here suffices on its own. --- ...15-04-17-Enums-match-mutation-and-moves.md | 28 +++++++++++++++---- 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 31b0c422e..4e36134f3 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -224,6 +224,14 @@ fn demo_guess_fixed() { } ``` +The `suggest_guess_fixed` function illustrates that `match` can handle +some cases early (and then immediately return from the function), +while computing whatever values are needed from the remaining cases +and letting them fall through to the remainder of the function +body. We can add this special case handling via `match` without fear +of overlooking a case, because `match` will enforce the case +analysis to be exhaustive. + ### Algebraic Data Types and Data Invariants Algebraic data types succinctly describe classes of data and allow one @@ -246,12 +254,12 @@ enum BinaryTree { (The `Box` type describes an owning reference to a heap-allocated instance of `V`; if you own a `Box`, then you also own the `V` it -contains, and can mutate it, lend out references to it, et cetera, and -when you finish with the box and let it fall out of scope, it will +contains, and can mutate it, lend out references to it, et cetera. +When you finish with the box and let it fall out of scope, it will automatically clean up the resources associated with the heap-allocated `V`.) -The above definition ensures that if we are given a `BinaryTree`, it +The above `enum` definition ensures that if we are given a `BinaryTree`, it will always fall into one of the above two cases. One will never encounter a `BinaryTree::Node` that does not have a left-hand child. There is no need to check for null. @@ -302,6 +310,11 @@ fn tree_demo_1() { } ``` +Algebraic data types establish structural invariants that are strictly +enforced by the language. (Even richer representation invariants can +be maintained via the use of modules and privacy; but let us not +digress from the topic at hand.) + ### Both expression- and statement-oriented Unlike many languages that offer pattern matching, Rust *embraces* @@ -378,6 +391,8 @@ fn num_to_ordinal_expr(x: u32) -> String { Sometimes expression-oriented style can yield very succinct code; other times the style requires contortions that can be avoided by writing in a statement-oriented style. +(The ability to return from one `match` arm in the +`suggest_guess_fixed` function earlier was an example of this.) Each of the styles has its use cases. Crucially, switching to a statement-oriented style in Rust does not sacrifice every other @@ -423,7 +438,8 @@ fn demo_sometimes_initialize() { The interesting thing about the above code is that after the `match`, we are not allowed to directly access `string`, because the compiler requires that the variable be initialized on every path through the -program. At the same time, we *can*, via `borrowed`, access data that +program before it can be accessed. +At the same time, we *can*, via `borrowed`, access data that may held *within* `string`, because a reference to that data is held by the `borrowed` variable when we go through the first match arm, and we ensure `borrowed` itself is initialized on every execution path @@ -436,9 +452,9 @@ data is deallocated if it was previously initialized.) In short, for soundness, the Rust language ensures that data is always initialized before it is referenced, but the designers have strived to -avoid requiring artificial coding patterns inserted solely to placate +avoid requiring artificial coding patterns adopted solely to placate Rust's static analyses (such as requiring one to initialize `string` -above with some dummy data just so that it can be borrowed later). +above with some dummy data, or requiring an expression-oriented style). ### Matching L-values From 9757c5ab76cc5d30695250c41dbb010f26346df1 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:28:29 +0200 Subject: [PATCH 099/386] couldn't resist adding a sherlock holmes quote. also, decided to point the docs link just to the root page, rather than into the reference manual. (reference.md manual is more complete w.r.t. `match` than e.g. trpl is, but long-term that will hopefully not be the case, and so over time I expect the reference.md to be the wrong thing to have long-lived links to.) --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 4e36134f3..0c9026a40 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -158,6 +158,11 @@ ownership and safety in general? ### Exhaustive case analysis +> ...when you have eliminated all which is impossible, +> then whatever remains, however improbable, must be the truth. +> +> -- Sherlock Holmes (Arthur Conan Doyle, "The Blanched Soldier") + `match` enforces exhaustive case analysis, which helps catch bugs in program logic and ensures that the value of a match expression is well-defined. @@ -624,6 +629,6 @@ expr; ... }` versus `match expr { id => { ... } }`, consult the Rust [documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). -[rust_docs]: https://doc.rust-lang.org/reference.html#match-expressions +[rust_docs]: https://doc.rust-lang.org/ [user group]: http://users.rust-lang.org/ [L_value]: https://doc.rust-lang.org/reference.html#lvalues,-rvalues-and-temporaries From 47ca71a1fe101b1a6eecba99fe3d58fe01f63769 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:37:46 +0200 Subject: [PATCH 100/386] improve tree ascii art. --- .../2015-04-17-Enums-match-mutation-and-moves.md | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 0c9026a40..d88a89889 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -287,17 +287,13 @@ fn tree_weight_v1(t: BinaryTree) -> i32 { } } -/// Looks like: +/// Returns tree that Looks like: /// -/// (4) -/// | -/// +--(2) -/// | | -/// | +--[1] -/// | | -/// | +--[3] -/// | -/// +--[5] +/// +----(4)---+ +/// | | +/// +-(2)-+ [5] +/// | | +/// [1] [3] /// fn sample_tree() -> BinaryTree { let l1 = Box::new(BinaryTree::Leaf(1)); From cb9b58dfda2b974b98a9414dc1ab8507e1883eaf Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:40:31 +0200 Subject: [PATCH 101/386] small cleanup --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index d88a89889..b15cce265 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -323,11 +323,13 @@ both statement- and expression-oriented programming. Many functional languages that offer pattern matching encourage one to write in an "expression-oriented style", where the focus is always on -the value returned by combining expressions and evaluating them, and +the values returned by evaluating combinations of expressions, and side-effects are discouraged. This style contrasts with imperative languages, which encourage a statement-oriented style that focuses on sequences of commands executed solely for their side-effects. +Rust excels in supporting both styles. + Consider writing a function which maps a non-negative integer to a string rendering it as an ordinal ("1st", "2nd", "3rd", ...). From 53d3cc1bd1f52dec22b07334e8eba297b39bdb3c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:42:00 +0200 Subject: [PATCH 102/386] cleanup --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index b15cce265..0851117d3 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -370,12 +370,12 @@ fn test_num_to_ordinal() { } ``` -The Rust compiler accepts the above program; this is notable because -its static analysis is ensuring both that `suffix` is always -initialized before we run the `format!` at the end *and* that `suffix` -is assigned at most once during the function's execution (because if -we could assign `suffix` multiple times, the compiler would force us -to mark `suffix` as mutable). +The Rust compiler accepts the above program. This is notable because +its static analyses ensure both: +* `suffix` is always initialized before we run the `format!` at the end +* `suffix` is assigned *at most once* during the function's execution (because if + we could assign `suffix` multiple times, the compiler would force us + to mark `suffix` as mutable). To be clear, the above program certainly *can* be written in an expression-oriented style in Rust; for example, like so: From 09507042b35158994a2a6f58ae4eac73ca2c6e13 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:42:41 +0200 Subject: [PATCH 103/386] cleanup --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 0851117d3..e582be225 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -373,6 +373,7 @@ fn test_num_to_ordinal() { The Rust compiler accepts the above program. This is notable because its static analyses ensure both: * `suffix` is always initialized before we run the `format!` at the end + of the function, and * `suffix` is assigned *at most once* during the function's execution (because if we could assign `suffix` multiple times, the compiler would force us to mark `suffix` as mutable). From 0f7bf0b33b9390082a2b5f1abc377ed4ea16db14 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:46:55 +0200 Subject: [PATCH 104/386] remove double-semicolon that has been irking me. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index e582be225..f40e80d0a 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -554,7 +554,7 @@ a successful match, *move* the value out of the original input and into `i`. Thus we can always conclude in such a case that `i` has type `T`, or "`i: T`". (For some types `T`, known as *copyable* `T` or "`T` implements `Copy`", the value will in fact be copied into `i` for such -identifier patterns; but in general types are not copyable; either +identifier patterns. But in general types are not copyable; either way, such bindings do mean that `i` has ownership of a value of type `T`.) From 1d3133d1ee609c4d8e476679a335dbc25a3a80d2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:49:50 +0200 Subject: [PATCH 105/386] Moved discussion of moving/copying into ident patterns into separate paragraph. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index f40e80d0a..c71d029fb 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -552,11 +552,13 @@ L-values works. When matching a value of type `T`, an identifier pattern `i` will, on a successful match, *move* the value out of the original input and into `i`. Thus we can always conclude in such a case that `i` has type -`T`, or "`i: T`". (For some types `T`, known as *copyable* `T` or "`T` -implements `Copy`", the value will in fact be copied into `i` for such -identifier patterns. But in general types are not copyable; either -way, such bindings do mean that `i` has ownership of a value of type -`T`.) +`T`, or "`i: T`". + +For some types `T`, known as *copyable* `T` (also pronounced "`T` +implements `Copy`"), the value will in fact be copied into `i` for such +identifier patterns. In the general case, an arbitrary type `T` is not copyable. +Either way, such identifier pattern bindings do mean that `i` has +ownership of a value of type `T`. Thus, the bindings of `payload` in `tree_weight_v2` both have type `i32`; the `i32` type implements `Copy`, so the weight is copied into From 5c08b9bc4536f910d45cbcf3f7db3e3d0fb3af46 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:51:54 +0200 Subject: [PATCH 106/386] cleanup --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index c71d029fb..3b5ededf9 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -574,7 +574,7 @@ Then we can pass those borrowed references to trees into the recursive calls to `tree_weight_v2`. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful -match, borrow a *mutable reference* `&mut T` into the input, (which allows +match, borrow a *mutable reference* into the input, `i: &mut T`, (which allows mutation and ensures there are no other active references to that data at the same time). An important detail here is the destructuring binding forms like `match` allows one to take mutable references to From 35adda5140d7035142dc907fcb57ffc12edbd4a2 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:52:48 +0200 Subject: [PATCH 107/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 3b5ededf9..1eed6066a 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -576,8 +576,8 @@ trees into the recursive calls to `tree_weight_v2`. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful match, borrow a *mutable reference* into the input, `i: &mut T`, (which allows mutation and ensures there are no other active references to that data -at the same time). An important detail here is the destructuring -binding forms like `match` allows one to take mutable references to +at the same time). An important detail here is a destructuring +binding form like `match` allows one to take mutable references to disjoint parts of the data simultaneously. This code demonstrates this concept by incrementing all of the From 4c0261e45603863d6dcf5d9d67d6ec00b079374d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:53:11 +0200 Subject: [PATCH 108/386] cleanup --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 1eed6066a..9e02b8cd3 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -576,7 +576,7 @@ trees into the recursive calls to `tree_weight_v2`. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful match, borrow a *mutable reference* into the input, `i: &mut T`, (which allows mutation and ensures there are no other active references to that data -at the same time). An important detail here is a destructuring +at the same time). A destructuring binding form like `match` allows one to take mutable references to disjoint parts of the data simultaneously. From 81e18a882bebf17773cad6701e8796848018d25d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 12:55:17 +0200 Subject: [PATCH 109/386] add hint about `const` to conclusion. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 9e02b8cd3..4fca08af5 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -624,8 +624,9 @@ and expressive power, while static analysis ensures that the resulting programs are safe. For more information -on details that were not covered here, such as binding via `ident @ -pattern`, or the potentially subtle difference between `{ let id = +on details that were not covered here, such as +defining new named constants, binding via `ident @ pattern`, +or the potentially subtle difference between `{ let id = expr; ... }` versus `match expr { id => { ... } }`, consult the Rust [documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). From 4d2c12a16e8cee00b135fb9c1c65583f0e115e06 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 16:30:56 +0200 Subject: [PATCH 110/386] add comments explaining the patterns in suggest_guess_smarter. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 4fca08af5..b3fbfaafd 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -128,10 +128,19 @@ struct GuessState { fn suggest_guess_smarter(s: GuessState) { match s { + // First arm only fires on Bingo; it binds `p` to last guess. GuessState { answer: Answer::Bingo, guess: p, .. } => { println!("we won with {}!", p); } + + // Second arm fires if answer was too low or too high. + // We want to find a new guess in the range (l..h), where: + // + // - If it was too low, then we want something higher, so we + // bind the guess to `l` and use our last high guess as `h`. GuessState { answer: Answer::Higher, low: _, guess: l, high: h } | + // - If it was too high, then we want something lower; bind + // the guess to `h` and use our last low guess as `l`. GuessState { answer: Answer::Lower, low: l, guess: h, high: _ } => { let mid = l + ((h - l) / 2); println!("lets try {} next", mid); From e6200ab9a1f6c957d0f7a49edfeb4d77eaea46f6 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 16:51:16 +0200 Subject: [PATCH 111/386] adopt suggestion from niko to use comments to explicitly tease apart the pieces of the patterns in suggest_guess_smarter. --- ...15-04-17-Enums-match-mutation-and-moves.md | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index b3fbfaafd..f870d75e1 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -130,6 +130,16 @@ fn suggest_guess_smarter(s: GuessState) { match s { // First arm only fires on Bingo; it binds `p` to last guess. GuessState { answer: Answer::Bingo, guess: p, .. } => { + // ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~ ~~ + // | | | | + // | | | ignore remaining fields + // | | | + // | | copy value of field `guess` into local variable `p` + // | | + // | Test that `answer field is equal to `Bingo` + // | + // Match against an instance of the struct `GuessState` + println!("we won with {}!", p); } @@ -138,10 +148,28 @@ fn suggest_guess_smarter(s: GuessState) { // // - If it was too low, then we want something higher, so we // bind the guess to `l` and use our last high guess as `h`. - GuessState { answer: Answer::Higher, low: _, guess: l, high: h } | // - If it was too high, then we want something lower; bind // the guess to `h` and use our last low guess as `l`. + GuessState { answer: Answer::Higher, low: _, guess: l, high: h } | GuessState { answer: Answer::Lower, low: l, guess: h, high: _ } => { + // ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ ~~~~~~~~ ~~~~~~~ + // | | | | | + // | | | | copy or ignore + // | | | | field `high`, + // | | | | as appropriate + // | | | | + // | | | copy field `guess` into + // | | | local variable `l` or `h`, + // | | | as appropriate + // | | | + // | | copy value of field `low` into local + // | | variable `l`, or ignore it, as appropriate + // | | + // | Test that `answer field is equal + // | to `Higher` or `Lower`, as appropriate + // | + // Match against an instance of the struct `GuessState` + let mid = l + ((h - l) / 2); println!("lets try {} next", mid); } From da23b9244fc89e27ac02795f59fc5400fe0d6995 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:22:47 +0200 Subject: [PATCH 112/386] Address niko feedback on use of the term "exhaustive." --- ...15-04-17-Enums-match-mutation-and-moves.md | 30 ++++++++----------- 1 file changed, 13 insertions(+), 17 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index f870d75e1..8a928837b 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -200,23 +200,19 @@ ownership and safety in general? > > -- Sherlock Holmes (Arthur Conan Doyle, "The Blanched Soldier") -`match` enforces exhaustive case analysis, which helps catch bugs in -program logic and ensures that the value of a match expression is -well-defined. - -Case analysis is an important problem solving technique: Dividing a -problem into some number of separate cases, and then analyzing each -case individually. - -For this method of problem solving to work, the cases must be -*collectively exhaustive*; otherwise, a case that was not covered -would mean a potential problem instance for which no solution has been -identified. - -This brings us to one of the fundamental restrictions of Rust's -`match` construct: the collection of cases must be exhaustive. In -other words, every possible input value must be covered by the pattern -for a least one arm in the match. +One useful way to tackle a complex problem is to break it down +into individual cases and analyze each case individually. +For this method of problem solving to work, the breakdown must be +*collectively exhaustive*; all of the cases you identified must +actually cover all possible scenarios. + +Using `enum` and `match` in Rust can aid this process, because +`match` enforces exhaustive case analysis: +Every possible input value for a `match` must be covered by the pattern +in a least one arm in the match. + +This helps catch bugs in program logic and ensures that the value of a +`match` expression is well-defined. So, for example, the following code is rejected at compile-time. From 8d4e660889e17e5841cbcb40b23493b1331f6e1a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:25:26 +0200 Subject: [PATCH 113/386] add bullet about exhaustiveness checking being a refactoring aid, as suggested by niko. --- .../2015-04-17-Enums-match-mutation-and-moves.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 8a928837b..8714499d4 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -237,9 +237,18 @@ Rust has this restriction for two reasons: general solution if the cases are exhaustive. Exhaustiveness-checking exposes logical errors. -* Second, since `match` is an expression form, exhaustiveness ensures -that such expressions always evaluates to a value of the correct type -(or jump elsewhere in the program, as illustrated here): +* Second, exhaustiveness-checking can act as a refactoring aid. During +the development process, I often add new variants for a particular +`enum` definition. The exhaustiveness-check helps points out all of +the `match` expressions were I only wrote the cases from the prior +version of the `enum` type. + +* Third, since `match` is an expression form, exhaustiveness ensures +that such expressions always evaluates to a value of the correct type, +or jump elsewhere in the program. + +The following code is a fixed version of the `suggest_guess_broken` +function we saw above; it directly illustrates "jumping elsewhere": ```rust fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { From f0a72062ad879535016bfad0defc98e3483a3921 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:28:20 +0200 Subject: [PATCH 114/386] I meant to commit this earlier. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 8714499d4..72e9e69ea 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -275,8 +275,10 @@ The `suggest_guess_fixed` function illustrates that `match` can handle some cases early (and then immediately return from the function), while computing whatever values are needed from the remaining cases and letting them fall through to the remainder of the function -body. We can add this special case handling via `match` without fear -of overlooking a case, because `match` will enforce the case +body. + +We can add such special case handling via `match` without fear +of overlooking a case, because `match` will force the case analysis to be exhaustive. ### Algebraic Data Types and Data Invariants From b24a3b1111612d4241a76b5e20ec6d9a3f9a1822 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:28:42 +0200 Subject: [PATCH 115/386] Make capitalization and alignment consistent, as suggested by niko. --- .../2015-04-17-Enums-match-mutation-and-moves.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 72e9e69ea..b05a3fe57 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -132,9 +132,9 @@ fn suggest_guess_smarter(s: GuessState) { GuessState { answer: Answer::Bingo, guess: p, .. } => { // ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~ ~~ // | | | | - // | | | ignore remaining fields + // | | | Ignore remaining fields // | | | - // | | copy value of field `guess` into local variable `p` + // | | Copy value of field `guess` into local variable `p` // | | // | Test that `answer field is equal to `Bingo` // | @@ -154,19 +154,19 @@ fn suggest_guess_smarter(s: GuessState) { GuessState { answer: Answer::Lower, low: l, guess: h, high: _ } => { // ~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~ ~~~~~~ ~~~~~~~~ ~~~~~~~ // | | | | | - // | | | | copy or ignore + // | | | | Copy or ignore // | | | | field `high`, // | | | | as appropriate // | | | | - // | | | copy field `guess` into + // | | | Copy field `guess` into // | | | local variable `l` or `h`, - // | | | as appropriate + // | | | as appropriate // | | | - // | | copy value of field `low` into local + // | | Copy value of field `low` into local // | | variable `l`, or ignore it, as appropriate // | | // | Test that `answer field is equal - // | to `Higher` or `Lower`, as appropriate + // | to `Higher` or `Lower`, as appropriate // | // Match against an instance of the struct `GuessState` From 5301ce1338732f099f5b13c959c9a7856c11a7ed Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:38:26 +0200 Subject: [PATCH 116/386] remove much of the jargon from the bullets in the intro. --- ...15-04-17-Enums-match-mutation-and-moves.md | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index b05a3fe57..88413a49c 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -26,24 +26,22 @@ In this post we explore how Rust processes such data via `match`. The crucial elements that `match` and its counterpart `enum` tie together are: -* Structural pattern matching of algebraic data types: The `match` - construct enables case analysis with ergonomics that are vastly - improved over that provided by a C or Java style `switch` statement. +* Structural pattern matching: case analysis with ergonomics vastly + improved over a C or Java style `switch` statement. -* Exhaustive case analysis, which ensures that no case is omitted +* Exhaustive case analysis: ensures that no case is omitted when processing an input. * `match` embraces both imperative and functional styles of - programming: The compiler's static analyses work hard to ensure - statement-oriented programming remains palatable, rather than - forcing everyone to adopt an expression-oriented mindset. + programming: you can continue using `break` statements, assignments, + et cetera, + rather than being forced to adopt an expression-oriented mindset. -* Destructuring bind of *L-values*: Rust encourages the developer to +* `match` "borrows" or "moves", as needed: Rust encourages the developer to think carefully about ownership and borrowing. To ensure that - processing data does not force one to give up ownership of a value + one is not forced to yield ownership of a value prematurely, `match` is designed with support for merely *borrowing* - substructure within its input (as opposed to always *moving* such - substructure). + substructure (as opposed to always *moving* such substructure). We cover each of the items above in detail below, but first we establish a foundation for the discussion: What does `match` look From f26018eaea31e9a6cacb4ed27502223220657f12 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:40:22 +0200 Subject: [PATCH 117/386] switch from "PREDICATE" to "PATTERNS" justification: this is not a formal model of the language. Even though *I* think of the whole thing as a predicate, it is just as likely to confuse people, especially since I do not even introduce side-conditions at this point. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 88413a49c..4644d4ea9 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -53,17 +53,17 @@ The `match` expression in Rust has this form: ```rust match INPUT_EXPRESSION { - PREDICATE_1 => RESULT_EXPRESSION_1, - PREDICATE_2 => RESULT_EXPRESSION_2, + PATTERNS_1 => RESULT_EXPRESSION_1, + PATTERNS_2 => RESULT_EXPRESSION_2, ... - PREDICATE_n => RESULT_EXPRESSION_n + PATTERNS_n => RESULT_EXPRESSION_n } ``` -where each of the `PREDICATE_i` contains at least one *pattern*. A +where each of the `PATTERNS_i` contains at least one *pattern*. A pattern describes a subset of the possible values to which `INPUT_EXPRESSION` could evaluate. -The syntax `PREDICATE => RESULT_EXPRESSION` is called a "match arm", +The syntax `PATTERNS => RESULT_EXPRESSION` is called a "match arm", or simply "arm". Patterns can match atomic values, like integers or characters; they From 02593b22ffcf20b92ca4e98afd11f0cfdfb53949 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:51:36 +0200 Subject: [PATCH 118/386] Tried to make the post less jargon-heavy. Many thanks to Mutabah, proc, libfud, asQuirrel, annodomini and the rest of `#rust` for the review feedback! --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 4644d4ea9..6e0a9c29d 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -8,7 +8,7 @@ description: "A tour of matching and enums in Rust." One of the primary goals of the Rust project is to enable safe systems programming. Systems programming usually implies imperative programming, which in turns often implies side-effects, reasoning -about shared, aliasable state, et cetera. +about shared state, et cetera. At the same time, to provide *safety*, Rust programs and data types must be structured in a way that allows static checking to ensure @@ -66,7 +66,7 @@ pattern describes a subset of the possible values to which The syntax `PATTERNS => RESULT_EXPRESSION` is called a "match arm", or simply "arm". -Patterns can match atomic values, like integers or characters; they +Patterns can match simple values like integers or characters; they can also match user-defined symbolic data, defined via `enum`. The below code demonstrates generating the next guess (poorly) in a number @@ -100,10 +100,10 @@ executable; you can cut-and-paste the code snippets into a file `demo.rs`, compile the file with `--test`, and run the resulting binary to see the tests run.) -Patterns can also match structured data (e.g. tuples, slices, user-defined +Patterns can also match [structured data] (e.g. tuples, slices, user-defined data types) via corresponding patterns. In such patterns, one often -binds substructure of the input to local variables (identifier patterns), -for use either in the arm's predicate or in its result. +binds parts of the input to local variables; +those variables can then be used in the result expression. The special `_` pattern matches any single value, and is often used as a catch-all; the special `..` pattern generalizes this by matching any @@ -627,7 +627,7 @@ values in a given tree. ```rust fn tree_grow(t: &mut BinaryTree) { - // ^~~~~~~~~~~~~~~ `&mut`: we have unaliased access to the tree + // ^~~~~~~~~~~~~~~ `&mut`: we have exclusive access to the tree match *t { BinaryTree::Leaf(ref mut payload) => *payload += 1, BinaryTree::Node(ref mut left, ref mut payload, ref mut right) => { @@ -673,6 +673,7 @@ expr; ... }` versus `match expr { id => { ... } }`, consult the Rust [documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). +[structured data]: http://en.wikipedia.org/wiki/Record_%28computer_science%29 [rust_docs]: https://doc.rust-lang.org/ [user group]: http://users.rust-lang.org/ [L_value]: https://doc.rust-lang.org/reference.html#lvalues,-rvalues-and-temporaries From e25a759dca1a64e70ea09a9350da39619f8279e3 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 17:57:53 +0200 Subject: [PATCH 119/386] Added acknowledgements of review helpers. :) --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6e0a9c29d..940ea2e85 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -673,6 +673,10 @@ expr; ... }` versus `match expr { id => { ... } }`, consult the Rust [documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). +(Many thanks to those who helped review this post, especially Aaron Turon +and Niko Matsakis, as well as +`Mutabah`, `proc`, `libfud`, `asQuirrel`, and `annodomini` from `#rust`.) + [structured data]: http://en.wikipedia.org/wiki/Record_%28computer_science%29 [rust_docs]: https://doc.rust-lang.org/ [user group]: http://users.rust-lang.org/ From bfdd20002981909ead18ecb0dd68a086c3b36e36 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:02:47 +0200 Subject: [PATCH 120/386] avoid naming number of elements in the bullet list. ;) --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 940ea2e85..7da70afbe 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -229,7 +229,7 @@ Many other languages offer a pattern matching construct (ML and various macro-based `match` implementations in Scheme both come to mind), but not all of them have this restriction. -Rust has this restriction for two reasons: +Rust has this restriction for these reasons: * First, as noted above, dividing a problem into cases only yields a general solution if the cases are exhaustive. Exhaustiveness-checking From 466ce858ad35f0efeedd094ce3f16251fa517d15 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:03:17 +0200 Subject: [PATCH 121/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 7da70afbe..6ab1abf64 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -238,7 +238,7 @@ exposes logical errors. * Second, exhaustiveness-checking can act as a refactoring aid. During the development process, I often add new variants for a particular `enum` definition. The exhaustiveness-check helps points out all of -the `match` expressions were I only wrote the cases from the prior +the `match` expressions where I only wrote the cases from the prior version of the `enum` type. * Third, since `match` is an expression form, exhaustiveness ensures From 4dbf9df543722569cf30ade3b57c433a83aae9be Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:03:58 +0200 Subject: [PATCH 122/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6ab1abf64..6d5b91d4e 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -242,8 +242,8 @@ the `match` expressions where I only wrote the cases from the prior version of the `enum` type. * Third, since `match` is an expression form, exhaustiveness ensures -that such expressions always evaluates to a value of the correct type, -or jump elsewhere in the program. +that such expressions always either evaluate to a value of the correct type, +*or* jump elsewhere in the program. The following code is a fixed version of the `suggest_guess_broken` function we saw above; it directly illustrates "jumping elsewhere": From fc2d18dc0605aabb86f11a50b4261d668ac7081f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:06:03 +0200 Subject: [PATCH 123/386] add reference for Algebraic Data Types so people can look up the term. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6d5b91d4e..18559caf3 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -279,9 +279,9 @@ We can add such special case handling via `match` without fear of overlooking a case, because `match` will force the case analysis to be exhaustive. -### Algebraic Data Types and Data Invariants +### Algebraic Data Types and Structural Invariants -Algebraic data types succinctly describe classes of data and allow one +[Algebraic data types] succinctly describe classes of data and allow one to encode rich structural invariants. An `enum` type allows one to define mutually-exclusive classes of @@ -678,6 +678,7 @@ and Niko Matsakis, as well as `Mutabah`, `proc`, `libfud`, `asQuirrel`, and `annodomini` from `#rust`.) [structured data]: http://en.wikipedia.org/wiki/Record_%28computer_science%29 +[Algebraic data types]: http://en.wikipedia.org/wiki/Algebraic_data_type [rust_docs]: https://doc.rust-lang.org/ [user group]: http://users.rust-lang.org/ [L_value]: https://doc.rust-lang.org/reference.html#lvalues,-rvalues-and-temporaries From 70b7ceb0f5ce4a8edea037c364bda60064fe1ec7 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:07:49 +0200 Subject: [PATCH 124/386] added link to above section. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 18559caf3..85c14e827 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -280,6 +280,7 @@ of overlooking a case, because `match` will force the case analysis to be exhaustive. ### Algebraic Data Types and Structural Invariants +[adts]: #algebraic-data-types-and-structural-invariants [Algebraic data types] succinctly describe classes of data and allow one to encode rich structural invariants. @@ -508,7 +509,7 @@ Matching an input can *borrow* input substructure, without taking ownership; this is crucial for matching a reference (e.g. a value of type `&T`). -The "Algebraic Data Types" section above described a tree datatype, and +The ["Algebraic Data Types" section][adts] above described a tree datatype, and showed a program that computed the sum of the integers in a tree instance. From ab09f522f18eeaff1ff78bc370e5ee8d0ec2dbad Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:08:24 +0200 Subject: [PATCH 125/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 85c14e827..b580f4fbb 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -313,7 +313,7 @@ encounter a `BinaryTree::Node` that does not have a left-hand child. There is no need to check for null. One *does* need to check whether a given `BinaryTree` is a `Leaf` or -is a `Node`, but the compiler statically ensure such checks are done: +is a `Node`, but the compiler statically ensures such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. From 04f9d064b376bcbb7551afd5fc16eb7aca44624d Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:11:00 +0200 Subject: [PATCH 126/386] add link to the `fn suggest_guess_fixed` example. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index b580f4fbb..583bb3ad2 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -245,6 +245,9 @@ version of the `enum` type. that such expressions always either evaluate to a value of the correct type, *or* jump elsewhere in the program. +#### Jumping out of a match +[jumping]: #jumping-out-of-a-match + The following code is a fixed version of the `suggest_guess_broken` function we saw above; it directly illustrates "jumping elsewhere": @@ -439,7 +442,7 @@ Sometimes expression-oriented style can yield very succinct code; other times the style requires contortions that can be avoided by writing in a statement-oriented style. (The ability to return from one `match` arm in the -`suggest_guess_fixed` function earlier was an example of this.) +`suggest_guess_fixed` function [earlier][jumping] was an example of this.) Each of the styles has its use cases. Crucially, switching to a statement-oriented style in Rust does not sacrifice every other From 6ee1e32f929468b6ce32773a8445ce3e9f389fe8 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:13:26 +0200 Subject: [PATCH 127/386] avoid using the term "L-value" prematurely. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 583bb3ad2..11a2dbf7c 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -506,7 +506,8 @@ avoid requiring artificial coding patterns adopted solely to placate Rust's static analyses (such as requiring one to initialize `string` above with some dummy data, or requiring an expression-oriented style). -### Matching L-values +### Matching without moving +[matching without moving]: #matching-without-moving Matching an input can *borrow* input substructure, without taking ownership; this is crucial for matching a reference (e.g. a value of From a4047a9c487367fd22a6403aa4ff44a23f369a7a Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Fri, 17 Apr 2015 18:25:59 +0200 Subject: [PATCH 128/386] break up dense text in Matching without Moving improve Matching without Moving section by breaking up dense text --- ...15-04-17-Enums-match-mutation-and-moves.md | 39 +++++++++++-------- 1 file changed, 22 insertions(+), 17 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 11a2dbf7c..14686d671 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -596,34 +596,39 @@ The only piece left is the `ref`-binding, which is a crucial part of how destructuring bind of L-values works. -When matching a value of type `T`, an identifier pattern `i` will, on -a successful match, *move* the value out of the original input and -into `i`. Thus we can always conclude in such a case that `i` has type -`T`, or "`i: T`". +* When matching a value of type `T`, an identifier pattern `i` will, on + a successful match, *move* the value out of the original input and + into `i`. Thus we can always conclude in such a case that `i` has type + `T` (or more succinctly, "`i: T`"). -For some types `T`, known as *copyable* `T` (also pronounced "`T` -implements `Copy`"), the value will in fact be copied into `i` for such -identifier patterns. In the general case, an arbitrary type `T` is not copyable. -Either way, such identifier pattern bindings do mean that `i` has -ownership of a value of type `T`. + For some types `T`, known as *copyable* `T` (also pronounced "`T` + implements `Copy`"), the value will in fact be copied into `i` for such + identifier patterns. (Note that in general, an arbitrary type `T` is not copyable.) + + Either way, such pattern bindings do mean that the variable `i` has + *ownership* of a value of type `T`. Thus, the bindings of `payload` in `tree_weight_v2` both have type `i32`; the `i32` type implements `Copy`, so the weight is copied into `payload` in both arms. -However, when matching a value of type `T`, a `ref`-pattern `ref i` -will, on a successful match, merely *borrow* a reference into the -matched data. In other words, a successful `ref i` match of a value of -type `T` will imply that `i: &T`. Thus, in the `Node` arm of +* However, when matching a value of type `T`, a `ref`-pattern `ref i` + will, on a successful match, merely *borrow* a reference into the + matched data. In other words, a successful `ref i` match of a value of + type `T` will imply that `i` has the type of a *reference* to `T` + (or more succinctly, "`i: &T`"). + +Thus, in the `Node` arm of `tree_weight_v2`, `left` will be a reference to the left-hand box (which holds a tree), and `right` will likewise reference the right-hand tree. -Then we can pass those borrowed references to -trees into the recursive calls to `tree_weight_v2`. + +We can pass these borrowed references to trees into the recursive calls to `tree_weight_v2`, +as the code demonstrates. Likewise, a `ref mut`-pattern (`ref mut i`) will, on a successful -match, borrow a *mutable reference* into the input, `i: &mut T`, (which allows +match, borrow a *mutable reference* into the input: `i: &mut T`. This allows mutation and ensures there are no other active references to that data -at the same time). A destructuring +at the same time. A destructuring binding form like `match` allows one to take mutable references to disjoint parts of the data simultaneously. From e528d4c6c136ef9b3bac61172d3f0946ece260ff Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Fri, 17 Apr 2015 18:28:43 +0200 Subject: [PATCH 129/386] aid flow into heavy definitions Added some surrounding text preparing the reader for some denseness. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 14686d671..6325f2207 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -596,6 +596,8 @@ The only piece left is the `ref`-binding, which is a crucial part of how destructuring bind of L-values works. +First, let us carefully state the meaning of a *non-ref* binding: + * When matching a value of type `T`, an identifier pattern `i` will, on a successful match, *move* the value out of the original input and into `i`. Thus we can always conclude in such a case that `i` has type @@ -612,7 +614,9 @@ Thus, the bindings of `payload` in `tree_weight_v2` both have type `i32`; the `i32` type implements `Copy`, so the weight is copied into `payload` in both arms. -* However, when matching a value of type `T`, a `ref`-pattern `ref i` +Now we are ready to state what a ref-binding is: + +* When matching an L-value of type `T`, a `ref`-pattern `ref i` will, on a successful match, merely *borrow* a reference into the matched data. In other words, a successful `ref i` match of a value of type `T` will imply that `i` has the type of a *reference* to `T` From 72b60f77e8e1a253a6d28490c931e25d73c62866 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:33:51 +0200 Subject: [PATCH 130/386] cleanup presentation of "for further reading" list in conclusion. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 6325f2207..420212a78 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -680,10 +680,15 @@ and expressive power, while static analysis ensures that the resulting programs are safe. For more information -on details that were not covered here, such as -defining new named constants, binding via `ident @ pattern`, -or the potentially subtle difference between `{ let id = -expr; ... }` versus `match expr { id => { ... } }`, consult the Rust +on details that were not covered here, such as: + +* defining new named constants, + +* binding via `ident @ pattern`, or + +* the potentially subtle difference between `{ let id = expr; ... }` versus `match expr { id => { ... } }`, + +consult the Rust [documentation][rust_docs], or quiz our awesome community (in `#rust` on IRC, or in the [user group]). From 380bb24f3993bc0f8aa82af354d8609184d7deed Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:36:27 +0200 Subject: [PATCH 131/386] make connection between adts and enums. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 420212a78..efa1baa55 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -286,7 +286,8 @@ analysis to be exhaustive. [adts]: #algebraic-data-types-and-structural-invariants [Algebraic data types] succinctly describe classes of data and allow one -to encode rich structural invariants. +to encode rich structural invariants. Rust uses `enum` and `struct` +definitions for this purpose. An `enum` type allows one to define mutually-exclusive classes of values. The examples shown above used `enum` for simple symbolic tags, From b498981748f6fc15a9976077e03b4cb5318fb75f Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:37:15 +0200 Subject: [PATCH 132/386] avoid saying "definitions define ..." --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index efa1baa55..bbe5f0def 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -291,7 +291,7 @@ definitions for this purpose. An `enum` type allows one to define mutually-exclusive classes of values. The examples shown above used `enum` for simple symbolic tags, -but in Rust, such definitions can define much richer classes of data. +but in Rust, enums can define much richer classes of data. For example, a binary tree is either a leaf, or an internal node with references to two child trees. Here is one way to encode a tree of From 26f79515254ce50d93e755227a4e70762afafc84 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 18:45:11 +0200 Subject: [PATCH 133/386] hint at the `use self::EnumType::*;` trick. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index bbe5f0def..112665d84 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -683,6 +683,8 @@ programs are safe. For more information on details that were not covered here, such as: +* how to say `Higher` instead of `Answer::Higher` in a pattern, + * defining new named constants, * binding via `ident @ pattern`, or From d50a79d5e46e1181e4ce1dc1bd2679632a705419 Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 19:06:47 +0200 Subject: [PATCH 134/386] fix formatting bug. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 112665d84..f192d4d83 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -100,7 +100,7 @@ executable; you can cut-and-paste the code snippets into a file `demo.rs`, compile the file with `--test`, and run the resulting binary to see the tests run.) -Patterns can also match [structured data] (e.g. tuples, slices, user-defined +Patterns can also match [structured data][structured data] (e.g. tuples, slices, user-defined data types) via corresponding patterns. In such patterns, one often binds parts of the input to local variables; those variables can then be used in the result expression. From 149c7f6cdd878a14bcbbd94d13e3a8914dda7f3a Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 19:07:19 +0200 Subject: [PATCH 135/386] remove tabs that snuck in somehow. --- ...15-04-17-Enums-match-mutation-and-moves.md | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index f192d4d83..8b9c7ff8c 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -89,9 +89,9 @@ fn suggest_guess(prior_guess: u32, answer: Answer) { #[test] fn demo_suggest_guess() { - suggest_guess(10, Answer::Higher); - suggest_guess(20, Answer::Lower); - suggest_guess(19, Answer::Bingo); + suggest_guess(10, Answer::Higher); + suggest_guess(20, Answer::Lower); + suggest_guess(19, Answer::Bingo); } ``` @@ -176,9 +176,9 @@ fn suggest_guess_smarter(s: GuessState) { #[test] fn demo_guess_state() { - suggest_guess_smarter(GuessState { - guess: 20, answer: Answer::Lower, low: 10, high: 1000 - }); + suggest_guess_smarter(GuessState { + guess: 20, answer: Answer::Lower, low: 10, high: 1000 + }); } ``` @@ -266,9 +266,9 @@ fn suggest_guess_fixed(prior_guess: u32, answer: Answer) { #[test] fn demo_guess_fixed() { - suggest_guess_fixed(10, Answer::Higher); - suggest_guess_fixed(20, Answer::Lower); - suggest_guess_fixed(19, Answer::Bingo); + suggest_guess_fixed(10, Answer::Higher); + suggest_guess_fixed(20, Answer::Lower); + suggest_guess_fixed(19, Answer::Bingo); } ``` @@ -460,13 +460,13 @@ fn sometimes_initialize(input: i32) { let borrowed: &str; // a reference to string data match input { 0...100 => { - // Construct a String on the fly... + // Construct a String on the fly... string = format!("input prints as {}", input); - // ... and then borrow from inside it. + // ... and then borrow from inside it. borrowed = &string[6..]; } _ => { - // String literals are *already* borrowed references + // String literals are *already* borrowed references borrowed = "expected between 0 and 100"; } } @@ -474,9 +474,9 @@ fn sometimes_initialize(input: i32) { // Below would cause compile-time error if uncommented... - // println!("string: {}", string); + // println!("string: {}", string); - // ...namely: error: use of possibly uninitialized variable: `string` + // ...namely: error: use of possibly uninitialized variable: `string` } #[test] From e0ea470625429f8695b9495b7343126d86bd318c Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Fri, 17 Apr 2015 19:22:26 +0200 Subject: [PATCH 136/386] fix typo. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index 8b9c7ff8c..bcf6e994e 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -321,7 +321,7 @@ is a `Node`, but the compiler statically ensures such checks are done: you cannot accidentally interpret the data of a `Leaf` as if it were a `Node`, nor vice versa. -Here is a function that increments all of the integers in a tree +Here is a function that sums all of the integers in a tree using `match`. ```rust From 165d3183e49fcdba3096e205dffe29203ee63bb5 Mon Sep 17 00:00:00 2001 From: Felix S Klock II Date: Fri, 17 Apr 2015 19:44:13 +0200 Subject: [PATCH 137/386] fix formatting bug github preview differs from our own blog rendering in how it handles bullet lists. --- _posts/2015-04-17-Enums-match-mutation-and-moves.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_posts/2015-04-17-Enums-match-mutation-and-moves.md b/_posts/2015-04-17-Enums-match-mutation-and-moves.md index bcf6e994e..60ed207ae 100644 --- a/_posts/2015-04-17-Enums-match-mutation-and-moves.md +++ b/_posts/2015-04-17-Enums-match-mutation-and-moves.md @@ -419,8 +419,10 @@ fn test_num_to_ordinal() { The Rust compiler accepts the above program. This is notable because its static analyses ensure both: + * `suffix` is always initialized before we run the `format!` at the end of the function, and + * `suffix` is assigned *at most once* during the function's execution (because if we could assign `suffix` multiple times, the compiler would force us to mark `suffix` as mutable). From 527256b93f43526bdbe6ac518398d198e1278d06 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 17 Apr 2015 10:55:27 -0700 Subject: [PATCH 138/386] Add header anchors --- _config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_config.yml b/_config.yml index ece89c2c2..6581330ec 100644 --- a/_config.yml +++ b/_config.yml @@ -11,5 +11,7 @@ github_username: rust-lang # Build settings highlighter: pygments markdown: redcarpet +redcarpet: + extensions: ["with_toc_data"] root: http://blog.rust-lang.org From 8c399bd06ac06160269016acef8dd362e4ff71cf Mon Sep 17 00:00:00 2001 From: Nick Hamann Date: Tue, 21 Apr 2015 16:25:14 -0500 Subject: [PATCH 139/386] Escape left paren so it isn't interpreted as Markdown link url --- _posts/2014-12-12-1.0-Timeline.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2014-12-12-1.0-Timeline.md b/_posts/2014-12-12-1.0-Timeline.md index c7b177705..df92779eb 100644 --- a/_posts/2014-12-12-1.0-Timeline.md +++ b/_posts/2014-12-12-1.0-Timeline.md @@ -15,7 +15,7 @@ produce Rust 1.0.0 final at least two cycles afterwards**: * Rust 1.0.0 -- One or more six-week cycles later We talked before about [why Rust is reaching 1.0], and also about the -[6-week train model] (with Nightly, Beta, and Stable channels) that will enable +[6-week train model] \(with Nightly, Beta, and Stable channels) that will enable us to deliver stability without stagnation. This post finishes the story by laying out the transition to this new release model and the stability guarantees it provides. From da8ccafb809198522280814fbd2702f5a5046358 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 23 Apr 2015 12:56:12 -0700 Subject: [PATCH 140/386] FFI and Rust --- _posts/2015-04-24-FFI-and-Rust.md | 265 ++++++++++++++++++++++++++++++ 1 file changed, 265 insertions(+) create mode 100644 _posts/2015-04-24-FFI-and-Rust.md diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-FFI-and-Rust.md new file mode 100644 index 000000000..0b4a03bab --- /dev/null +++ b/_posts/2015-04-24-FFI-and-Rust.md @@ -0,0 +1,265 @@ +--- +layout: post +title: "FFI and Rust" +author: Alex Crichton +description: "Zero-cost and safe FFI in Rust" +--- + + +Rust's quest for world domination was never destined to happen overnight, so +Rust needs to be able to interoperate with the existing world just as easily +as it talks to itself. To solve this problem, **Rust lets you communicate with C +APIs at no extra cost while providing strong safety guarantees**. + +This is also referred to as Rust's foreign function interface (FFI) and is the +method by which Rust communicates with other programming languages. Following +Rust's design principles, this is a **zero cost abstraction** where function +calls between Rust and C have identical performance to C function calls. FFI +bindings can also leverage language features such as ownership and borrowing to +provide a **safe interface**. + +In this post we'll explore how to encapsulate unsafe FFI calls to C in safe, +zero-cost abstractions by looking at some examples of interacting with C. +Working with C is, however, just an example, as we'll also see how Rust can +easily talk to languages like Python and Ruby just as seamlessly as C. + +### Talking to C + +First, let's start with an example of calling C code from Rust and then +demonstrate that Rust imposes no additional overhead. Starting off simple, +here's a C program which will simply double all the input it's given: + +```c +int double_input(int input) { + return input * 2; +} +``` + +To call this from Rust, one would write this program: + +```rust +extern crate libc; + +extern { + fn double_input(input: libc::c_int) -> libc::c_int; +} + +fn main() { + let input = 4; + let output = unsafe { double_input(input) }; + println!("{} * 2 = {}", input, output); +} +``` + +And that's it! You can try this out for yourself by [checking out the code on +GitHub][rust2c] and running `cargo run` from that directory. At the source level +we can see that there's no burden in calling an external function, and we'll see +soon that the generated code indeed has no overhead. There are, however, a few +subtle aspects of this Rust program so let's cover each piece in detail. + +[rust2c]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/rust-to-c + +First up we see `extern crate libc`. [This crate][libc] provides many useful +type definitions for FFI bindings when talking with C, and it is necessary +to ensure that both C and Rust agree on the types crossing the language +boundary. + +[libc]: https://crates.io/crates/libc + +This leads us nicely into the next part of the program: + +```rust +extern { + fn double_input(input: libc::c_int) -> libc::c_int; +} +``` + +In Rust this is a **declaration** of an externally available function. You can +think of this along the lines of a C header file. Here's where the compiler +learns about the inputs and outputs of the function, and you can see above that +this matches our definition in C. Next up we have the main body of the program: + +```rust +fn main() { + let input = 4; + let output = unsafe { double_input(input) }; + println!("{} * 2 = {}", input, output); +} +``` + +We see one of the crucial aspects of FFI in Rust here, the `unsafe` block. The +compiler knows nothing about the implementation of `double_input`, so it must +assume that memory unsafety *could* happen in this scenario. This may seem +limiting, but Rust has just the right set of tools to allow consumers to not +worry about `unsafe` (more on this in a moment). + +Now that we've seen how to call a C function from Rust, let's see if we can +verify this claim of zero overhead. Almost all programming languages can call +into C one way or another, but it often comes at a cost with runtime type +conversions or perhaps some language runtime juggling. To get a handle on what +Rust is doing, let's go straight to the assembly code of the above `main` +function's call to `double_input`: + +``` +mov $0x4,%edi +callq 3bc30 +``` + +And as before, that's it! Here we can see that calling a C function from Rust +involves precisely one call instruction after moving the arguments into place, +exactly the same cost as it would be in C. + +### Safe Abstractions + +One of Rust's core design principles is its emphasis on ownership, and FFI is no +exception here. When binding a C library in Rust you not only have the benefit +of 0 overhead, but you are also able to make it *safer* than C can! Bindings +can leverage the ownership and borrowing principles in Rust to codify comments +typically found in a C header about how its API should be used. + +For example, consider a C library for parsing a tarball. This library will +expose functions to read the contents of each file in the tarball, probably +something along the lines of: + +```c +// Gets the data for a file in the tarball at the given index, returning NULL if +// it does not exist. The `size` pointer is filled in with the size of the file +// if successful. +const char *tarball_file_data(tarball_t *tarball, unsigned index, size_t *size); +``` + +This function is implicitly making assumptions about how it can be used, +however, by assuming that the `char*` pointer returned cannot outlive the input +tarball. When bound in Rust, this API might look like this instead: + +```rust +pub struct Tarball { raw: *mut tarball_t } + +impl Tarball { + pub fn file(&self, index: u32) -> Option<&[u8]> { + unsafe { + let mut size = 0; + let data = tarball_file_data(self.raw, index as libc::c_uint, + &mut size); + if data.is_null() { + None + } else { + Some(slice::from_raw_parts(data as *const u8, size as usize)) + } + } + } +} +``` + +Here the `*mut tarball_t` pointer is *owned by* a `Tarball`, so we already have +rich knowledge about the lifetime of the resource. Additionally, the `file` +method returns a **borrowed slice** whose lifetime is connected to the same +lifetime as the source tarball itself. This is Rust's way of indicating that the +returned data cannot outlive the tarball, statically preventing bugs that may be +encountered when just using C. + +A key aspect of the Rust binding here is that it is a safe function! Although it +has an `unsafe` implementation (due to calling an FFI function), this interface +is safe to call and will not cause tough-to-track-down segfaults. And don't +forget, all of this is coming at 0 cost as the raw types in C are representable +in Rust with no extra allocations or overhead. + +### Talking to Rust + +A major feature of Rust is that it does not have a garbage collector or +runtime, and one of the benefits of this is that Rust can be called from C with +no setup at all. This means that the zero overhead FFI not only applies when +Rust calls into C, but also when C calls into Rust! + +Let's take the example above, but reverse the roles of each language. As before, +all the code below is [available on GitHub][c2rust]. First we'll start off with +our Rust code: + +[c2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/c-to-rust + +```rust +#[no_mangle] +pub extern fn double_input(input: i32) -> i32 { + input * 2 +} +``` + +As with the Rust code before, there's not a whole lot here but there are some +subtle aspects in play. First off we've got our function definition with a +`#[no_mangle]` attribute. This instructs the compiler to not mangle the symbol +name for the function `double_input`. Rust employs name mangling similar to C++ +to ensure that libraries do not clash with one another, and this attributes +means that you don't have to guess a symbol name like +`double_input::h485dee7f568bebafeaa` from C. + +Next we've got our function definition, and the most interesting part about +this is the keyword `extern`. This is a specialized form of specifying the [ABI +for a function][abi-fn] which enables the function to be compatible with a C +function call. + +[abi-fn]: http://doc.rust-lang.org/reference.html#extern-functions + +Finally, if you [take a look at the `Cargo.toml`][cargo-toml] you'll see that +this library is not compiled as a normal Rust library (rlib) but instead as a +static archive which Rust calls a 'staticlib'. This enables all the relevant +Rust code to be linked statically into the C program we're about to produce. + +[cargo-toml]: https://github.com/alexcrichton/rust-ffi-examples/blob/master/c-to-rust/Cargo.toml#L8 + +Now that we've got our Rust library squared away, let's write our C program +which will call Rust. + +```c +#include +#include + +extern int32_t double_input(int32_t input); + +int main() { + int input = 4; + int output = double_input(input); + printf("%d * 2 = %d\n", input, output); + return 0; +} +``` + +Here we can see that C, like Rust, needs to declare the `double_input` function +that Rust defined. Other than that though everything is ready to go! If you run +`make` from the [directory on GitHub][c2rust] you'll see these examples getting +compiled and linked together and the final executable should run and print +`4 * 2 = 8`. + +Rust's lack of a garbage collector and runtime enables this seamless transition +from C to Rust. The external C code does not need to perform any setup on Rust's +behalf, making the transition that much cheaper. + +### Beyond C + +Up to now we've seen how FFI in Rust has zero overhead and how we can use Rust's +concept of ownership to write safe bindings to C libraries. If you're not using +C, however, you're still in luck! These features of Rust enable it to also be +called from [Python][py2rust], [Ruby][rb2rust], [Javascript][js2rust], and many +more languages. + +[py2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/python-to-rust +[rb2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/ruby-to-rust +[js2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/node-to-rust + +A common desire for writing C code in these languages is to speed up some +component of a library or application that's performance critical. With the +features of Rust we've seen here, however, Rust is just as suitable for this +sort of usage. One of Rust's first production users, +[Skylight](https://www.skylight.io), was able to improve the performance and +memory usage of their data collection agent almost instantly by just using Rust, +and the Rust code is all published as a Ruby gem. + +Moving from a language like Python and Ruby down to C to optimize performance is +often quite difficult as it's tough to ensure that the program won't crash in a +difficult-to-debug way. Rust, however, not only brings zero cost FFI, but *also* +the same safety guarantees the original source language, enabling this sort of +optimization to happen even more frequently! + +FFI is just one of many tools in the toolbox of Rust, but it's a key component +to Rust's adoption as it allows Rust to seamlessly integrate with existing code +bases today. I'm personally quite excited to see the benefits of Rust reach as +many projects as possible! From f998c8761bada6fc7f44aaf0e4f2e446f64f35c1 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 24 Apr 2015 09:10:47 -0700 Subject: [PATCH 141/386] Editing pass --- _posts/2015-04-24-FFI-and-Rust.md | 146 +++++++++++++++++------------- 1 file changed, 83 insertions(+), 63 deletions(-) diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-FFI-and-Rust.md index 0b4a03bab..4a53cf582 100644 --- a/_posts/2015-04-24-FFI-and-Rust.md +++ b/_posts/2015-04-24-FFI-and-Rust.md @@ -5,29 +5,31 @@ author: Alex Crichton description: "Zero-cost and safe FFI in Rust" --- - Rust's quest for world domination was never destined to happen overnight, so -Rust needs to be able to interoperate with the existing world just as easily -as it talks to itself. To solve this problem, **Rust lets you communicate with C -APIs at no extra cost while providing strong safety guarantees**. - -This is also referred to as Rust's foreign function interface (FFI) and is the -method by which Rust communicates with other programming languages. Following -Rust's design principles, this is a **zero cost abstraction** where function -calls between Rust and C have identical performance to C function calls. FFI -bindings can also leverage language features such as ownership and borrowing to -provide a **safe interface**. +Rust needs to be able to interoperate with the existing world just as easily as +it talks to itself. In particular, **Rust makes it easy to communicate with C +APIs without overhead, and to leverage its ownership system to provide much +stronger safety guarantees for those APIs at the same time**. + +In more detail, Rust's *foreign function interface* (FFI) is the way that it +communicated with other languages. Following Rust's design principles, the FFI +provides a **zero cost abstraction** where function calls between Rust and C +have identical performance to C function calls. FFI bindings can also leverage +language features such as ownership and borrowing to provide a **safe +interface** that enforces protocols around pointers and other resources. These +protocols usually appear only in the documentation for C APIs -- at best -- but +Rust makes them explicit. In this post we'll explore how to encapsulate unsafe FFI calls to C in safe, -zero-cost abstractions by looking at some examples of interacting with C. -Working with C is, however, just an example, as we'll also see how Rust can -easily talk to languages like Python and Ruby just as seamlessly as C. +zero-cost abstractions. Working with C is, however, just an example; we'll also +see how Rust can easily talk to languages like Python and Ruby just as +seamlessly as with C. -### Talking to C +### Rust talking to C -First, let's start with an example of calling C code from Rust and then -demonstrate that Rust imposes no additional overhead. Starting off simple, -here's a C program which will simply double all the input it's given: +Let's start with a simple example of calling C code from Rust and then +demonstrate that Rust imposes no additional overhead. Here's a C program which +will simply double all the input it's given: ```c int double_input(int input) { @@ -35,7 +37,7 @@ int double_input(int input) { } ``` -To call this from Rust, one would write this program: +To call this from Rust, you might write a program like this: ```rust extern crate libc; @@ -51,18 +53,18 @@ fn main() { } ``` -And that's it! You can try this out for yourself by [checking out the code on -GitHub][rust2c] and running `cargo run` from that directory. At the source level -we can see that there's no burden in calling an external function, and we'll see -soon that the generated code indeed has no overhead. There are, however, a few -subtle aspects of this Rust program so let's cover each piece in detail. +And that's it! You can try this out for yourself by +[checking out the code on GitHub][rust2c] and running `cargo run` from that +directory. **At the source level we can see that there's no burden in calling an +external function beyond stating its signature, and we'll see soon that the +generated code indeed has no overhead, either.** There are, however, a few +subtle aspects of this Rust program, so let's cover each piece in detail. [rust2c]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/rust-to-c -First up we see `extern crate libc`. [This crate][libc] provides many useful -type definitions for FFI bindings when talking with C, and it is necessary -to ensure that both C and Rust agree on the types crossing the language -boundary. +First up we see `extern crate libc`. [The libc crate][libc] provides many useful +type definitions for FFI bindings when talking with C, and it makes it easy to +ensure that both C and Rust agree on the types crossing the language boundary. [libc]: https://crates.io/crates/libc @@ -89,9 +91,12 @@ fn main() { We see one of the crucial aspects of FFI in Rust here, the `unsafe` block. The compiler knows nothing about the implementation of `double_input`, so it must -assume that memory unsafety *could* happen in this scenario. This may seem -limiting, but Rust has just the right set of tools to allow consumers to not -worry about `unsafe` (more on this in a moment). +assume that memory unsafety *could* happen whenever you call a foreign function. +The `unsafe` block is how the programmer takes responsibility for ensuring +safety -- you are promising that the actual call you make will not, in fact, +violate memory safety, and thus that Rust's basic guarantees are upheld. This +may seem limiting, but Rust has just the right set of tools to allow consumers +to not worry about `unsafe` (more on this in a moment). Now that we've seen how to call a C function from Rust, let's see if we can verify this claim of zero overhead. Almost all programming languages can call @@ -111,11 +116,11 @@ exactly the same cost as it would be in C. ### Safe Abstractions -One of Rust's core design principles is its emphasis on ownership, and FFI is no -exception here. When binding a C library in Rust you not only have the benefit -of 0 overhead, but you are also able to make it *safer* than C can! Bindings -can leverage the ownership and borrowing principles in Rust to codify comments -typically found in a C header about how its API should be used. +Most features in Rust tie into its core concept of ownership, and the FFI is no +exception. When binding a C library in Rust you not only have the benefit of zero +overhead, but you are also able to make it *safer* than C can! **Bindings can +leverage the ownership and borrowing principles in Rust to codify comments +typically found in a C header about how its API should be used.** For example, consider a C library for parsing a tarball. This library will expose functions to read the contents of each file in the tarball, probably @@ -151,25 +156,35 @@ impl Tarball { } ``` -Here the `*mut tarball_t` pointer is *owned by* a `Tarball`, so we already have -rich knowledge about the lifetime of the resource. Additionally, the `file` -method returns a **borrowed slice** whose lifetime is connected to the same -lifetime as the source tarball itself. This is Rust's way of indicating that the -returned data cannot outlive the tarball, statically preventing bugs that may be -encountered when just using C. - -A key aspect of the Rust binding here is that it is a safe function! Although it -has an `unsafe` implementation (due to calling an FFI function), this interface -is safe to call and will not cause tough-to-track-down segfaults. And don't -forget, all of this is coming at 0 cost as the raw types in C are representable -in Rust with no extra allocations or overhead. - -### Talking to Rust - -A major feature of Rust is that it does not have a garbage collector or -runtime, and one of the benefits of this is that Rust can be called from C with -no setup at all. This means that the zero overhead FFI not only applies when -Rust calls into C, but also when C calls into Rust! +Here the `*mut tarball_t` pointer is *owned by* a `Tarball`, which is +responsible for any destruction and cleanup. So we already have rich knowledge +about the lifetime of the resource: if you have access to a `Tarball`, you know +that the pointer inside must still be valid. Additionally, the `file` method +returns a **borrowed slice** whose lifetime is implicitly connected to the +lifetime of the source tarball itself (the `&self` argument). This is Rust's way +of indicating that the returned slice can only be used within the lifetime of +the tarball, which in turn means that the slice will always point to valid +memory. Thus, Rust statically prevents dangling pointer bugs that are easy to +make when working directly with C. (If you're not familiar with this kind of +borrowing in Rust, have a look at Yehuda Katz's [blog post] on ownership.) + +[blog post]: http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ + +A key aspect of the Rust binding here is that it is a safe function, meaning +that callers do not have to use `unsafe` blocks to invoke it! Although it has an +`unsafe` *implementation* (due to calling an FFI function), the *interface* uses +borrowing to guarantee that no memory unsafety can occur in any Rust code that +uses it. That is, due to Rust's static checking, it's simply not possible to +cause a segfault using the API on the Rust side. And don't forget, all of this +is coming at zero cost: the raw types in C are representable in Rust with no +extra allocations or overhead. + +### C talking to Rust + +**Despite guaranteeing memory safety, Rust does not have a garbage collector or +runtime, and one of the benefits of this is that Rust code can be called from C +with no setup at all.** This means that the zero overhead FFI not only applies +when Rust calls into C, but also when C calls into Rust! Let's take the example above, but reverse the roles of each language. As before, all the code below is [available on GitHub][c2rust]. First we'll start off with @@ -185,10 +200,10 @@ pub extern fn double_input(input: i32) -> i32 { ``` As with the Rust code before, there's not a whole lot here but there are some -subtle aspects in play. First off we've got our function definition with a +subtle aspects in play. First off, we've labeled our function definition with a `#[no_mangle]` attribute. This instructs the compiler to not mangle the symbol name for the function `double_input`. Rust employs name mangling similar to C++ -to ensure that libraries do not clash with one another, and this attributes +to ensure that libraries do not clash with one another, and this attribute means that you don't have to guess a symbol name like `double_input::h485dee7f568bebafeaa` from C. @@ -245,10 +260,13 @@ more languages. [rb2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/ruby-to-rust [js2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/node-to-rust -A common desire for writing C code in these languages is to speed up some -component of a library or application that's performance critical. With the -features of Rust we've seen here, however, Rust is just as suitable for this -sort of usage. One of Rust's first production users, +When writing code in these languages, you sometimes want to speed up some +component that's performance critical, but in the past this often required +dropping all the way to C, and thereby giving up the memory safety, high-level +abstractions, and ergonomics of these languages. + +The fact that Rust can talk to easily with C, however, means that it is also +viable for this sort of usage. One of Rust's first production users, [Skylight](https://www.skylight.io), was able to improve the performance and memory usage of their data collection agent almost instantly by just using Rust, and the Rust code is all published as a Ruby gem. @@ -256,8 +274,10 @@ and the Rust code is all published as a Ruby gem. Moving from a language like Python and Ruby down to C to optimize performance is often quite difficult as it's tough to ensure that the program won't crash in a difficult-to-debug way. Rust, however, not only brings zero cost FFI, but *also* -the same safety guarantees the original source language, enabling this sort of -optimization to happen even more frequently! +makes it possible to retain the same safety guarantees as the original source +language. In the long run, this should make it much easier for programmers in +these languages to drop down and do some systems programming to squeeze out +critical performance when they need it. FFI is just one of many tools in the toolbox of Rust, but it's a key component to Rust's adoption as it allows Rust to seamlessly integrate with existing code From 805b38fd131880ea2816ac263e418849af962809 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 09:44:21 -0700 Subject: [PATCH 142/386] Call out community libs --- _posts/2015-04-24-FFI-and-Rust.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-FFI-and-Rust.md index 4a53cf582..565aeabf9 100644 --- a/_posts/2015-04-24-FFI-and-Rust.md +++ b/_posts/2015-04-24-FFI-and-Rust.md @@ -179,6 +179,19 @@ cause a segfault using the API on the Rust side. And don't forget, all of this is coming at zero cost: the raw types in C are representable in Rust with no extra allocations or overhead. +Rust's amazing community has already built some substantial safe bindings around +existing C libraries, including [OpenSSL][rust-openssl], [libgit2][git2-rs], +[libdispatch][dispatch], [libcurl][curl-rust], [sdl2][sdl2], [Unix APIs][nix], +and [libsodium][sodiumoxide]. + +[rust-openssl]: https://crates.io/crates/openssl +[git2-rs]: https://crates.io/crates/git2 +[curl-rust]: https://crates.io/crates/curl +[dispatch]: https://crates.io/crates/dispatch +[sdl2]: https://crates.io/crates/sdl2 +[nix]: https://crates.io/crates/nix +[sodiumoxide]: https://crates.io/crates/sodiumoxide + ### C talking to Rust **Despite guaranteeing memory safety, Rust does not have a garbage collector or From 3d2d4595f6dc396586b3a933b69ab330da1fc91b Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 09:45:04 -0700 Subject: [PATCH 143/386] Add some dashes --- _posts/2015-04-24-FFI-and-Rust.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-FFI-and-Rust.md index 565aeabf9..22351525f 100644 --- a/_posts/2015-04-24-FFI-and-Rust.md +++ b/_posts/2015-04-24-FFI-and-Rust.md @@ -13,7 +13,7 @@ stronger safety guarantees for those APIs at the same time**. In more detail, Rust's *foreign function interface* (FFI) is the way that it communicated with other languages. Following Rust's design principles, the FFI -provides a **zero cost abstraction** where function calls between Rust and C +provides a **zero-cost abstraction** where function calls between Rust and C have identical performance to C function calls. FFI bindings can also leverage language features such as ownership and borrowing to provide a **safe interface** that enforces protocols around pointers and other resources. These @@ -101,7 +101,7 @@ to not worry about `unsafe` (more on this in a moment). Now that we've seen how to call a C function from Rust, let's see if we can verify this claim of zero overhead. Almost all programming languages can call into C one way or another, but it often comes at a cost with runtime type -conversions or perhaps some language runtime juggling. To get a handle on what +conversions or perhaps some language-runtime juggling. To get a handle on what Rust is doing, let's go straight to the assembly code of the above `main` function's call to `double_input`: From 3af8d6a209d50de1b02b13e60e8d1b74e89acd89 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 09:50:19 -0700 Subject: [PATCH 144/386] Close up acknowledgements a bit more --- _posts/2015-04-24-FFI-and-Rust.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-FFI-and-Rust.md index 22351525f..f1d694c98 100644 --- a/_posts/2015-04-24-FFI-and-Rust.md +++ b/_posts/2015-04-24-FFI-and-Rust.md @@ -7,7 +7,7 @@ description: "Zero-cost and safe FFI in Rust" Rust's quest for world domination was never destined to happen overnight, so Rust needs to be able to interoperate with the existing world just as easily as -it talks to itself. In particular, **Rust makes it easy to communicate with C +it talks to itself. For this reason, **Rust makes it easy to communicate with C APIs without overhead, and to leverage its ownership system to provide much stronger safety guarantees for those APIs at the same time**. @@ -182,7 +182,9 @@ extra allocations or overhead. Rust's amazing community has already built some substantial safe bindings around existing C libraries, including [OpenSSL][rust-openssl], [libgit2][git2-rs], [libdispatch][dispatch], [libcurl][curl-rust], [sdl2][sdl2], [Unix APIs][nix], -and [libsodium][sodiumoxide]. +and [libsodium][sodiumoxide]. This list is also growing quite rapidly on +[crates.io][crates-io], so your favorite C library may already be bound or will +be bound soon! [rust-openssl]: https://crates.io/crates/openssl [git2-rs]: https://crates.io/crates/git2 @@ -191,6 +193,7 @@ and [libsodium][sodiumoxide]. [sdl2]: https://crates.io/crates/sdl2 [nix]: https://crates.io/crates/nix [sodiumoxide]: https://crates.io/crates/sodiumoxide +[crates-io]: https://crates.io ### C talking to Rust From fb731f5bbe1020dffe6f535182739cb63525af80 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 09:52:35 -0700 Subject: [PATCH 145/386] Rename post title --- ...4-FFI-and-Rust.md => 2015-04-24-Rust-Once-Run-Everywhere.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename _posts/{2015-04-24-FFI-and-Rust.md => 2015-04-24-Rust-Once-Run-Everywhere.md} (99%) diff --git a/_posts/2015-04-24-FFI-and-Rust.md b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md similarity index 99% rename from _posts/2015-04-24-FFI-and-Rust.md rename to _posts/2015-04-24-Rust-Once-Run-Everywhere.md index f1d694c98..439b675cb 100644 --- a/_posts/2015-04-24-FFI-and-Rust.md +++ b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md @@ -1,6 +1,6 @@ --- layout: post -title: "FFI and Rust" +title: "Rust Once, Run Everywhere" author: Alex Crichton description: "Zero-cost and safe FFI in Rust" --- From 939bc4348a96bc294827c2e2b20399275affcfca Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 10:16:27 -0700 Subject: [PATCH 146/386] Trim down a paragraph a bit --- _posts/2015-04-24-Rust-Once-Run-Everywhere.md | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md index 439b675cb..03c0116f5 100644 --- a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md +++ b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md @@ -11,14 +11,14 @@ it talks to itself. For this reason, **Rust makes it easy to communicate with C APIs without overhead, and to leverage its ownership system to provide much stronger safety guarantees for those APIs at the same time**. -In more detail, Rust's *foreign function interface* (FFI) is the way that it -communicated with other languages. Following Rust's design principles, the FFI -provides a **zero-cost abstraction** where function calls between Rust and C -have identical performance to C function calls. FFI bindings can also leverage -language features such as ownership and borrowing to provide a **safe -interface** that enforces protocols around pointers and other resources. These -protocols usually appear only in the documentation for C APIs -- at best -- but -Rust makes them explicit. +To communicate with other languages, Rust provides a *foreign function +interface* (FFI). Following Rust's design principles, the FFI provides a +**zero-cost abstraction** where function calls between Rust and C have identical +performance to C function calls. FFI bindings can also leverage language +features such as ownership and borrowing to provide a **safe interface** that +enforces protocols around pointers and other resources. These protocols usually +appear only in the documentation for C APIs -- at best -- but Rust makes them +explicit. In this post we'll explore how to encapsulate unsafe FFI calls to C in safe, zero-cost abstractions. Working with C is, however, just an example; we'll also @@ -157,16 +157,14 @@ impl Tarball { ``` Here the `*mut tarball_t` pointer is *owned by* a `Tarball`, which is -responsible for any destruction and cleanup. So we already have rich knowledge -about the lifetime of the resource: if you have access to a `Tarball`, you know -that the pointer inside must still be valid. Additionally, the `file` method +responsible for any destruction and cleanup, so we already have rich knowledge +about the lifetime of the tarball's memory. Additionally, the `file` method returns a **borrowed slice** whose lifetime is implicitly connected to the lifetime of the source tarball itself (the `&self` argument). This is Rust's way of indicating that the returned slice can only be used within the lifetime of -the tarball, which in turn means that the slice will always point to valid -memory. Thus, Rust statically prevents dangling pointer bugs that are easy to +the tarball, statically preventing dangling pointer bugs that are easy to make when working directly with C. (If you're not familiar with this kind of -borrowing in Rust, have a look at Yehuda Katz's [blog post] on ownership.) +borrowing in Rust, have a look at Yehuda Katz's [blog post on ownership].) [blog post]: http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ From 83b5b1250e33dffeda2ea6a2ae6b28a664ceabe5 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 24 Apr 2015 13:30:03 -0400 Subject: [PATCH 147/386] Add missing link to ownership blog post. --- _posts/2015-04-24-Rust-Once-Run-Everywhere.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md index 03c0116f5..4322af45e 100644 --- a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md +++ b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md @@ -184,6 +184,7 @@ and [libsodium][sodiumoxide]. This list is also growing quite rapidly on [crates.io][crates-io], so your favorite C library may already be bound or will be bound soon! +[blog post on ownership]: http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ [rust-openssl]: https://crates.io/crates/openssl [git2-rs]: https://crates.io/crates/git2 [curl-rust]: https://crates.io/crates/curl From b49d5e267797950d11b3649ff8aa08f90ce5788f Mon Sep 17 00:00:00 2001 From: Pascal Hertleif Date: Fri, 24 Apr 2015 21:51:21 +0200 Subject: [PATCH 148/386] Enable SmartyPants for Better Typography MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Enables transforming things like "--" to "–" and "we'll" to "we’ll". --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 6581330ec..184e02dbe 100644 --- a/_config.yml +++ b/_config.yml @@ -12,6 +12,6 @@ github_username: rust-lang highlighter: pygments markdown: redcarpet redcarpet: - extensions: ["with_toc_data"] + extensions: ["with_toc_data", "smart"] root: http://blog.rust-lang.org From 45111b156ffae80aa24da1d1231f1fc1cb00ad98 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Fri, 24 Apr 2015 16:09:26 -0700 Subject: [PATCH 149/386] Correct JavaScript spelling --- _posts/2015-04-24-Rust-Once-Run-Everywhere.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md index 4322af45e..1d824a57d 100644 --- a/_posts/2015-04-24-Rust-Once-Run-Everywhere.md +++ b/_posts/2015-04-24-Rust-Once-Run-Everywhere.md @@ -268,7 +268,7 @@ behalf, making the transition that much cheaper. Up to now we've seen how FFI in Rust has zero overhead and how we can use Rust's concept of ownership to write safe bindings to C libraries. If you're not using C, however, you're still in luck! These features of Rust enable it to also be -called from [Python][py2rust], [Ruby][rb2rust], [Javascript][js2rust], and many +called from [Python][py2rust], [Ruby][rb2rust], [JavaScript][js2rust], and many more languages. [py2rust]: https://github.com/alexcrichton/rust-ffi-examples/tree/master/python-to-rust From 3340ee90beed8605fcdddc9a044a6c08117b72de Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 11 May 2015 09:57:53 -0700 Subject: [PATCH 150/386] Blog post on traits --- _posts/2015-05-11-traits.md | 420 ++++++++++++++++++++++++++++++++++++ 1 file changed, 420 insertions(+) create mode 100644 _posts/2015-05-11-traits.md diff --git a/_posts/2015-05-11-traits.md b/_posts/2015-05-11-traits.md new file mode 100644 index 000000000..3d0b98dd1 --- /dev/null +++ b/_posts/2015-05-11-traits.md @@ -0,0 +1,420 @@ +--- +layout: post +title: "Abstraction without overhead: traits in Rust" +author: Aaron Turon +description: "The vision of Rust's traits for zero-cost abstraction" +--- + +[Previous posts][fearless] have covered two pillars of Rust's design: + +* Memory safety without garbage collection +* Concurrency without data races + +This post begins exploring the third pillar: + +* **Abstraction without overhead** + +One of the mantras of C++, one of the qualities that make it a good fit for +systems programming, is its principle of zero-cost abstraction: + +> C++ implementations obey the zero-overhead principle: What you don't use, you +> don't pay for [Stroustrup, 1994]. And further: What you do use, you couldn't +> hand code any better. +> +> -- Stroustrup + +This mantra did not always apply to Rust, which for example used to have +mandatory garbage collection. But over time Rust's ambitions have gotten +ever lower-level, and zero-cost abstraction is now a core principle. + +The cornerstone of abstraction in Rust is *traits*: + +* **Traits are Rust's sole notion of interface**. A trait can be implemented by + multiple types, and in fact new traits can provide implementations for + existing types. On the flip side, when you want to abstract over an unknown + type, traits are how you specify the few concrete things you need to know + about that type. + +* **Traits can be statically dispatched**. Like C++ templates, you can have + the compiler generate a separate copy of an abstraction for each way it is + instantiated. This comes back to the C++ mantra of "What you do use, you + couldn't hand code any better" -- the abstraction ends up completely erased. + +* **Traits can be dynamically dispatched**. Sometimes you really do need an + indirection, and so it doesn't make sense to "erase" an abstraction at + runtime. The *same* notion of interface -- the trait -- can also be used when + you want to dispatch at runtime. + +* **Traits solve a variety of additional problems beyond simple abstraction**. + They are used as "markers" for types, like the `Send` marker described + [in a previous post][fearless]. They can be used to define "extension methods" + -- that is, to add methods to an externally-defined type. They largely obviate + the need for traditional method overloading. And they provide a simple scheme + for operator overloading. + +All told, the trait system is the secret sauce that gives Rust the ergonomic, +expressive feel of high-level languages while retaining low-level control over +code execution and data representation. + +This post will walk through each of the above points at a high level, to give +you a sense for how the design achieves these goals, without getting too bogged +down in the details. + +### Background: methods in Rust + +> Before delving into traits, we need to look at a small but important detail of +> the language: the difference between methods and functions. + +Rust offers both methods and free-standing functions, which are very +closely related: + +```rust +struct Point { + x: f64; + y: f64, +} + +// a free-standing function that converts a (borrowed) point to a string +fn point_to_string(point: &Point) -> String { ... } + +// an "inherent impl" block defines the methods available directly on a type +impl Point { + // this method is available on any Point, and automatically borrows the + // Point value + fn to_string(&self) -> String { ... } +} +``` + +Methods like `to_string` above are called "inherent" methods, because they: + +* Are tied to a single concrete "self" type (specified via the `impl` block header). +* Are *automatically* available on any value of that type -- that is, unlike + functions, inherent methods are always "in scope". + +The first parameter for a method is always an explicit "self", which is either +`self`, `&mut self`, or `&self` depending on the +[level of ownership required][socket]. Methods are invoked using the `.` +notation familiar from object-oriented programming, and the self parameter is +*implicitly borrowed* as per the form of `self` used in the method: + +```rust +let p = Point { x: 1.2, y: -3.7 }; +let s1 = point_to_string(&p); // calling a free function, explicit borrow +let s2 = p.to_string(); // calling a method, implicit borrow as &p +``` + +Methods and their auto-borrowing are an important aspect of the ergonomics of +Rust, supporting "fluent" APIs like the one for spawning processes: + +```rust +let child = Command::new("/bin/cat") + .arg("rusty-ideas.txt") + .current_dir("/Users/aturon") + .stdout(Stdio::piped()) + .spawn(); +``` + +### Traits are interfaces + +Interfaces specify the expectations that one piece of code has on another, +allowing each to be switched out independently. For traits, this specification +largely revolves around methods. + +Take, for example, the following simple trait for hashing: + +```rust +trait Hash { + fn hash(&self) -> u64; +} +``` + +In order to implement this trait for a given type, you must provide a `hash` +method with matching signature: + +```rust +impl Hash for bool { + fn hash(&self) -> u64 { + if *self { 0 } else { 1 } + } +} + +impl Hash for i64 { + fn hash(&self) -> u64 { + *self as u64 + } +} +``` + +Unlike interfaces in languages like Java, C# or Scala, new traits can be implemented +for existing types (as with `Hash` above). **Code in upstream crates can be +adapted to interfaces in downstream crates**. + +Unlike inherent methods, trait methods are in scope only when their trait +is. But assuming `Hash` is in scope, you can write `true.hash()`, so +implementing a trait extends the set of methods available on a type. + +And... that's it! Defining and implementing a trait is really nothing more than +abstracting out a common interface satisfied by more than one type. + +### Static dispatch + +Things get more interesting on the other side -- consuming a trait. The most +common way of doing so is through *generics*: + +```rust +fn print_hash(t: &T) { + println!("The hash is {}", t.hash()) +} +``` + +The `print_hash` function is generic over an unknown type `T`, but requires that +`T` implements the `Hash` trait. That means we can use it with `bool` and `i64` +values: + +```rust +print_hash(&true); // instantiates T = bool +print_hash(&12_i64); // instantiates T = i64 +``` + +**Generics are compiled away, resulting in static dispatch**. That is, as with +C++ templates, the compiler will generate *two copies* of the `print_hash` +method to handle the above code, one for each concrete argument type. That in +turn means that the internal call to `t.hash()` -- the point where the +abstraction is actually used -- has zero cost: it will be compiled to a direct, +static call to the relevant implementation. + +This compilation model isn't so useful for a function like `print_hash`, but +it's *very* useful for more realistic uses of hashing. Suppose we also introduce +a trait for equality comparison: + +```rust +trait Eq { + fn eq(&self, other: &Self) -> bool; +} +``` + +(The reference to `Self` here will resolve to whatever type we implement the +trait for; in `impl Eq for bool` it will refer to `bool`.) + +We can then define a hash map that is generic over a type `T` implementing both +`Hash` and `Eq`: + +```rust +struct HashMap { ... } +``` + +The static compilation model for generics will then yield several benefits: + +* Each use of `HashMap` with concrete `Key` and `Value` types will result in a + different concrete `HashMap` type, which means that `HashMap` can lay out the + keys and values in-line (without indirection) in its buckets. This saves on + space and indirections, and improves cache locality. + +* Each method on `HashMap` will likewise generate specialized code. That means + there is no extra cost dispatching to calls to `hash` and `eq`, as above. It + also means that the optimizer gets to work with the fully concrete code -- + that is, from the point of view of the optimizer, *there is no abstraction*. + +Altogether, just as in C++ templates, these aspects of generics mean that you +can write quite high-level abstractions that are *guaranteed* to compile down to +fully concrete code that "you couldn't hand code any better". + +**But, unlike with C++ templates, clients of traits are fully type-checked in +advance**. That is, when you compile `HashMap` in isolation, its code is +checked *once* for type correctness against the abstract `Hash` and `Eq` traits, +rather than being checked repeatedly when applied to concrete types. That means +earlier, clearer compilation errors for library authors, and less typechecking +overhead for clients. + +#### Conditional trait implementation + +Generics also make it possible to implement a trait *conditionally*: + +```rust +struct Pair { + first: A, + second: B, +} + +impl Hash for Pair { + fn hash(&self) -> u64 { + self.first.hash() + .xor(self.second.hash()) + .wrapping_mul(0x100000001b3); + } +} +``` + +Here, the `Pair` type implements `Hash` if, and only if, its components +do. Conditional implementation enables flexible reuse of code: it would be a +shame to have to introduce separate `Pair` types that varied by the traits their +components implement. It's such a common pattern in Rust that there is built-in +support for generating certain kinds of "mechanical" implementations automatically: + +```rust +#[derive(Hash)] +struct Pair { .. } +``` + +### Dynamic dispatch + +We've seen one compilation model for traits, where all abstraction is compiled +away statically. But sometimes abstraction isn't just about reuse or modularity +-- **sometimes abstraction plays an essential role at runtime that can't be +compiled away**. + +For example, GUI frameworks often involve callbacks for responding to events, +such as mouse clicks: + +```rust +trait ClickCallback { + fn on_click(&self, x: i64, y: i64); +} +``` + +It's also common for GUI elements to allow multiple callbacks to be registered +for a single event. With generics, you might imagine writing: + +```rust +struct Button { + listeners: Vec, + ... +} +``` + +but the problem is immediately apparent: that would mean that each button is +specialized to precisely one implementor of `ClickCallback`, and that the type +of the button reflects that type. That's not at all what we wanted! Instead, +we'd like a single `Button` type with a set of *heterogeneous* listeners, each +potentially a different concrete type, but each one implementing +`ClickCallback`. + +One immediate difficulty here is that, if we're talking about a heterogeneous +group of types, *each one will have a distinct size* -- so how can we even lay +out the internal vector? The answer is the usual one: indirection. We'll store +*pointers* to callbacks in the vector: + +```rust +struct Button { + listeners: Vec>, + ... +} +``` + +Here, we are using the `ClickCallback` trait as if it were a type. Actually, in +Rust, [traits *are* types, but they are "unsized"][dst5], which roughly means +that they are only allowed to show up behind a pointer like `Box` (which points +onto the heap) or `&` (which can point anywhere). + +In Rust, a type like `&ClickCallback` or `Box` is called a "trait +object", and includes a pointer to an instance of a type `T` implementing +`ClickCallback`, *and* a vtable: a pointer to `T`'s implementation of each +method in the trait (here, just `on_click`). That information is enough to +dispatch calls to methods correctly at runtime, and to ensure uniform +representation for all `T`. So `Button` is compiled just once, and the +abstraction lives on at runtime. + +Static and dynamic dispatch are complementary tools, each appropriate for +different scenarios. **Rust's traits provide a single, simple notion of +interface that can be used in both styles, with minimal, predictable +costs**. Trait objects satisfy Stroustrup's "pay as you go" principle: you have +vtables when you need them, but the same trait can be compiled away statically +when you don't. + +### The many uses of traits + +We've seen a lot of the mechanics and basic use of traits above, but they also +wind up playing a few other important roles in Rust. Here's a taste: + +* **Closures**. Somewhat like the `ClickCallback` trait, closures in Rust are + simply particular traits. You can read more about how this works in + Huon Wilson's [in-depth post][closures] on the topic. + +* **Extension methods**. Traits can be used to extend an existing type (defined + elsewhere) with new methods, for convenience, similarly to C#'s extension + methods. This falls directly out of the scoping rules for traits: you just + define the new methods in a trait, provide an implementation for the type in + question, and *voila*, the method is available. + +* **Markers**. Rust has a handful of "markers" that classify types: `Send`, + `Sync`, `Copy`, `Sized`. These markers are just *traits* with empty bodies, + which can then be used in both generics and trait objects. Markers can be + defined in libraries, and they automatically provide `#[derive]`-style + implementations: if all of a types components are `Send`, for example, so is + the type. As we saw [before][fearless], these markers can be very powerful: + the `Send` marker is how Rust guarantees thread safety. + +* **Overloading**. Rust does not support traditional overloading where the same + method is defined with multiple signatures. But traits provide much of the + benefit of overloading: if a method is defined generically over a trait, it + can be called with any type implementing that trait. Compared to traditional + overloading, this has two advantages. First, it means the overloading is not + [ad hoc][adhoc]: once you understand a trait, you immediately understand the + overloading pattern of any APIs using it. Second, it is *extensible*: you can + effectively provide new overloads downstream from a method by providing new + trait implementations. + +* **Operators**. Rust allows you to overload operators like `+` on your own + types. Each of the operators is defined by a corresponding standard library + trait, and any type implementing the trait automatically provides the operator + as well. + +The point: **despite their seeming simplicity, traits are a unifying concept +that supports a wide range of use cases and patterns, without having to pile on +additional language features.** + +### The future + +One of the primary ways that languages tend to evolve is in their abstraction +facilities, and Rust is no exception: many of our [post-1.0 priorities][post1] +are extensions of the trait system in one direction or another. Here are some +highlights. + +* **Statically dispatched outputs**. Right now, it's possible for functions to + use generics for their parameters, but there's no equivalent for their + results: you cannot say "this function returns a value of some type that + implements the `Iterator` trait" and have that abstraction compiled away. + This is particularly problematic when you want to return a closure that you'd + like to be statically-dispatched -- you simply can't, in today's Rust. We want + to make this possible, and [have some ideas already][impl-trait]. + +* **Specialization**. Rust does not allow overlap between trait implementations, + so there is never ambiguity about which code to run. On the other hand, there + are some cases where you can give a "blanket" implementation for a wide range + of types, but would then like to provide a more specialized implementation for + a few cases, often for performance reasons. We hope to propose a design in the + near future. + +* **Higher-kinded types** (HKT). Traits today can only be applied to *types*, + not *type constructors* -- that is, to things like `Vec`, not to `Vec` + itself. This limitation makes it difficult to provide a good set of container + traits, which are therefore not included in the current standard library. HKT + is a major, cross-cutting feature that will represent a big step forward in + Rust's abstraction capabilities. + +* **Efficient re-use**. Finally, while traits provide some mechanisms for + reusing code (which we didn't cover above), there are still some patterns of + reuse that don't fit well into the language today -- notably, object-oriented + hierarchies found in things like the DOM, GUI frameworks, and many + games. Accommodating these use cases without adding too much overlap or + complexity is a very interesting design problem, and one that Niko Matsakis + has started a separate [blog series][virtual] about. It's not yet clear + whether this can all be done with traits, or whether some other ingredients + are needed. + +Of course, we're at the eve of the 1.0 release, and it will take some time for +the dust to settle, and for the community to have enough experience to start +landing these extensions. But that makes it an exciting time to get involved: +from influencing the design at this early stage, to working on implementation, +to trying out different use cases in your own code -- we'd love to have your +help! + +[zero-cost-cpp]: http://www.stroustrup.com/abstraction-and-machine.pdf +[fearless]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html +[dst5]: http://smallcultfollowing.com/babysteps/blog/2014/01/05/dst-take-5/ +[adhoc]: dl.acm.org/citation.cfm?id=75283 +[socket]: http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ +[post1]: http://internals.rust-lang.org/t/priorities-after-1-0/1901 +[virtual]: http://smallcultfollowing.com/babysteps/blog/2015/05/05/where-rusts-enum-shines/ +[closures]: http://huonw.github.io/blog/2015/05/finding-closure-in-rust/ +[impl-trait]: https://github.com/rust-lang/rfcs/pull/105 From e7952bbd4dd7fb1e4fd56c073956c5b72d38a6f7 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 11 May 2015 10:13:33 -0700 Subject: [PATCH 151/386] Clarifications to traits post --- _posts/2015-05-11-traits.md | 71 +++++++++++++++++++------------------ 1 file changed, 37 insertions(+), 34 deletions(-) diff --git a/_posts/2015-05-11-traits.md b/_posts/2015-05-11-traits.md index 3d0b98dd1..318c95f07 100644 --- a/_posts/2015-05-11-traits.md +++ b/_posts/2015-05-11-traits.md @@ -145,9 +145,9 @@ impl Hash for i64 { } ``` -Unlike interfaces in languages like Java, C# or Scala, new traits can be implemented -for existing types (as with `Hash` above). **Code in upstream crates can be -adapted to interfaces in downstream crates**. +Unlike interfaces in languages like Java, C# or Scala, **new traits can be +implemented for existing types** (as with `Hash` above). That means abstractions +can be created after-the-fact, and applied to existing libraries. Unlike inherent methods, trait methods are in scope only when their trait is. But assuming `Hash` is in scope, you can write `true.hash()`, so @@ -181,7 +181,13 @@ C++ templates, the compiler will generate *two copies* of the `print_hash` method to handle the above code, one for each concrete argument type. That in turn means that the internal call to `t.hash()` -- the point where the abstraction is actually used -- has zero cost: it will be compiled to a direct, -static call to the relevant implementation. +static call to the relevant implementation: + +```rust +// The compiled code: +__print_hash_bool(&true); // invoke specialized bool version directly +__print_hash_i64(&true); // invoke specialized i64 version directly +``` This compilation model isn't so useful for a function like `print_hash`, but it's *very* useful for more realistic uses of hashing. Suppose we also introduce @@ -214,6 +220,7 @@ The static compilation model for generics will then yield several benefits: there is no extra cost dispatching to calls to `hash` and `eq`, as above. It also means that the optimizer gets to work with the fully concrete code -- that is, from the point of view of the optimizer, *there is no abstraction*. + In particular, static dispatch allows for *inlining* across uses of generics. Altogether, just as in C++ templates, these aspects of generics mean that you can write quite high-level abstractions that are *guaranteed* to compile down to @@ -226,36 +233,6 @@ rather than being checked repeatedly when applied to concrete types. That means earlier, clearer compilation errors for library authors, and less typechecking overhead for clients. -#### Conditional trait implementation - -Generics also make it possible to implement a trait *conditionally*: - -```rust -struct Pair { - first: A, - second: B, -} - -impl Hash for Pair { - fn hash(&self) -> u64 { - self.first.hash() - .xor(self.second.hash()) - .wrapping_mul(0x100000001b3); - } -} -``` - -Here, the `Pair` type implements `Hash` if, and only if, its components -do. Conditional implementation enables flexible reuse of code: it would be a -shame to have to introduce separate `Pair` types that varied by the traits their -components implement. It's such a common pattern in Rust that there is built-in -support for generating certain kinds of "mechanical" implementations automatically: - -```rust -#[derive(Hash)] -struct Pair { .. } -``` - ### Dynamic dispatch We've seen one compilation model for traits, where all abstraction is compiled @@ -330,6 +307,32 @@ wind up playing a few other important roles in Rust. Here's a taste: simply particular traits. You can read more about how this works in Huon Wilson's [in-depth post][closures] on the topic. +* **Conditional APIs**. Generics make it possible to implement a trait + conditionally: + + ```rust + struct Pair { first: A, second: B } + + impl Hash for Pair { + fn hash(&self) -> u64 { + self.first.hash() + .xor(self.second.hash()) + .wrapping_mul(0x100000001b3); + } + } + ``` + + Here, the `Pair` type implements `Hash` if, and only if, its components do -- + allowing the single `Pair` type to be used in different contexts, while + supporting the largest API available for each context. It's such a common + pattern in Rust that there is built-in support for generating certain kinds of + "mechanical" implementations automatically: + + ```rust + #[derive(Hash)] + struct Pair { .. } + ``` + * **Extension methods**. Traits can be used to extend an existing type (defined elsewhere) with new methods, for convenience, similarly to C#'s extension methods. This falls directly out of the scoping rules for traits: you just From 43deed8bb7721d2cd7b6342b23df15adaf04e1c2 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 11 May 2015 10:15:48 -0700 Subject: [PATCH 152/386] Further cleanup for traits post --- _posts/2015-05-11-traits.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2015-05-11-traits.md b/_posts/2015-05-11-traits.md index 318c95f07..883783f87 100644 --- a/_posts/2015-05-11-traits.md +++ b/_posts/2015-05-11-traits.md @@ -70,7 +70,7 @@ closely related: ```rust struct Point { - x: f64; + x: f64, y: f64, } @@ -231,7 +231,7 @@ advance**. That is, when you compile `HashMap` in isolation, its code is checked *once* for type correctness against the abstract `Hash` and `Eq` traits, rather than being checked repeatedly when applied to concrete types. That means earlier, clearer compilation errors for library authors, and less typechecking -overhead for clients. +overhead (i.e., faster compilation) for clients. ### Dynamic dispatch @@ -415,7 +415,7 @@ help! [zero-cost-cpp]: http://www.stroustrup.com/abstraction-and-machine.pdf [fearless]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html [dst5]: http://smallcultfollowing.com/babysteps/blog/2014/01/05/dst-take-5/ -[adhoc]: dl.acm.org/citation.cfm?id=75283 +[adhoc]: http://dl.acm.org/citation.cfm?id=75283 [socket]: http://blog.skylight.io/rust-means-never-having-to-close-a-socket/ [post1]: http://internals.rust-lang.org/t/priorities-after-1-0/1901 [virtual]: http://smallcultfollowing.com/babysteps/blog/2015/05/05/where-rusts-enum-shines/ From 114acea8e460d0e0b354e36c046774f7da5cd029 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 11 May 2015 10:28:28 -0700 Subject: [PATCH 153/386] Simplify hashing example in traits post --- _posts/2015-05-11-traits.md | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/_posts/2015-05-11-traits.md b/_posts/2015-05-11-traits.md index 883783f87..8aef9e481 100644 --- a/_posts/2015-05-11-traits.md +++ b/_posts/2015-05-11-traits.md @@ -312,12 +312,9 @@ wind up playing a few other important roles in Rust. Here's a taste: ```rust struct Pair { first: A, second: B } - impl Hash for Pair { fn hash(&self) -> u64 { - self.first.hash() - .xor(self.second.hash()) - .wrapping_mul(0x100000001b3); + self.first.hash() ^ self.second.hash() } } ``` From 5d9a50977187e191063ea0d53ce432a616b9b762 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 11 May 2015 11:54:07 -0700 Subject: [PATCH 154/386] Minor fixes to traits post --- _posts/2015-05-11-traits.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-05-11-traits.md b/_posts/2015-05-11-traits.md index 8aef9e481..2f4753fa5 100644 --- a/_posts/2015-05-11-traits.md +++ b/_posts/2015-05-11-traits.md @@ -186,7 +186,7 @@ static call to the relevant implementation: ```rust // The compiled code: __print_hash_bool(&true); // invoke specialized bool version directly -__print_hash_i64(&true); // invoke specialized i64 version directly +__print_hash_i64(&12_i64); // invoke specialized i64 version directly ``` This compilation model isn't so useful for a function like `print_hash`, but @@ -348,7 +348,7 @@ wind up playing a few other important roles in Rust. Here's a taste: method is defined with multiple signatures. But traits provide much of the benefit of overloading: if a method is defined generically over a trait, it can be called with any type implementing that trait. Compared to traditional - overloading, this has two advantages. First, it means the overloading is not + overloading, this has two advantages. First, it means the overloading is less [ad hoc][adhoc]: once you understand a trait, you immediately understand the overloading pattern of any APIs using it. Second, it is *extensible*: you can effectively provide new overloads downstream from a method by providing new From 214e4102767271e46572420ad513b12126df4d51 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 09:20:51 -0700 Subject: [PATCH 155/386] Add 1.0 announcement --- _posts/2015-05-15-Rust-1.0.md | 328 ++++++++++++++++++++++++++++++++++ 1 file changed, 328 insertions(+) create mode 100644 _posts/2015-05-15-Rust-1.0.md diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md new file mode 100644 index 000000000..e8203f89c --- /dev/null +++ b/_posts/2015-05-15-Rust-1.0.md @@ -0,0 +1,328 @@ +--- +layout: post +title: "Announcing Rust 1.0" +author: The Rust Core Team +--- + +Today we are very proud to announce the +[1.0 release of Rust][relnotes], a new programming language aiming to +make it easier to build reliable, efficient systems. **Rust combines +low-level control over performance with high-level convenience and +safety guarantees**. Better yet, it achieves these goals without +requiring a garbage collector or runtime, making it possible to +[use Rust libraries as a "drop-in replacement" for C][ffi]. If you'd +like to experiment with Rust, the +["Getting Started" section of the Rust book][book] is your best bet. + +What makes Rust different from other languages is its type system, +which represents a refinement and codification of "best practices" +that have been hammered out by generations of C and C++ +programmers. As such, Rust has something to offer for both experienced +systems programmers and newcomers alike: experienced programmers will +find they save time they would have spent debugging, whereas newcomers +can write low-level code without worrying about minor mistakes leading +to mysterious crashes. + +### What does it mean for Rust to be 1.0? + +The current Rust language is the result of a lot of iteration and +experimentation. The process has worked out well for us: Rust today is +both simpler and more powerful than we originally thought would be +possible. But all that experimentation also made it difficult to +maintain a Rust project, since the language and standard library were +constantly changing. + +**The 1.0 release marks the end of that churn.** This release is the +official beginning of our [commitment to stability][stable], and as +such it offers a firm foundation for building applications and +libraries. From this point forward, breaking changes are largely out +of scope (some [caveats] apply, such as compiler bugs). + +That said, releasing 1.0 doesn't mean that the Rust language is +"done". We have many [improvements in store][priorities]. In fact, the +Nightly builds of Rust already demonstrates [improvements to][24965] +[compile][24615] [times][25323] (with more to come) and includes work +on new APIs and language features, like [`std::fs`][1044] and +[associated constants][23606]. + +To help ensure that compiler and language improvements make their way +out into the ecosystem at large as quickly as possible, we've adopted +a [train-based][train] release model. This means that we'll be issuing +regular releases every six weeks, just like evergreen browsers. **To +kick off that process, we are also releasing Rust 1.1 beta today, +simultaneously with Rust 1.0.** + +### Cargo and crates.io + +Building a real project is about more than just writing code -- it's +also about managing dependencies. [Cargo][cargo], the Rust package +manager and build system, is designed to make this easy. Using Cargo, +downloading and installing new libraries is as simple as adding one +line to your manifest. + +Of course, to use a dependency, you first have to find it. This is +where [crates.io] comes in -- crates.io is a central package +repository for Rust code. It makes it easy to search for other +people's packages or to publish your own. + +Since we [announced cargo and crates.io][cargo] approximately six +months ago, the number of packages has been growing +steadily. Nonetheless, it's still early days, and there are still lots +of great packages yet to be written. If you're interested in building +a libary that will take the Rust world by storm, there's no time like +the present! + +### Open Source and Open Governance + +Rust has been an open-source project from the start. Over the last few +years, we've been constantly looking for ways to make our governance +more open and community driven. Since we introduced the +[RFC process][rfcs] a little over a year ago, all major decisions +about Rust are written up and discussed in the open in the form of a +RFC. Recently, we adopted a [new governance model][1068], which +establishes a set of subteams, each responsible for RFCs in one +particular area. If you'd like help shape the future of Rust, we +encourage you to get involved, either by uploading libraries to +[crates.io], commenting on RFCs, or +[writing code for Rust itself][contributing]. + +We'd like to give a special thank you to the following people, each of +whom contributed changes since our previous release (the +[complete list of contributors][AUTHORS] is here): + +- `Aaron Gallagher <_@habnab.it>` +- `Aaron Turon ` +- `Abhishek Chanda ` +- `Adolfo Ochagavía ` +- `Alex Burka ` +- `Alex Crichton ` +- `Alex Quach ` +- `Alexander Polakov ` +- `Andrea Canciani ` +- `Andreas Martens ` +- `Andreas Tolfsen ` +- `Andrei Oprea ` +- `Andrew Paseltiner ` +- `Andrew Seidl ` +- `Andrew Straw ` +- `Andrzej Janik ` +- `Aram Visser ` +- `Ariel Ben-Yehuda ` +- `Augusto Hack ` +- `Avdi Grimm ` +- `Barosl Lee ` +- `Ben Ashford ` +- `Ben Gesoff ` +- `Björn Steinbrink ` +- `Brad King ` +- `Brendan Graetz ` +- `Brett Cannon ` +- `Brian Anderson ` +- `Brian Campbell ` +- `Carlos Galarza ` +- `Carol (Nichols || Goulding) ` +- `Carol Nichols ` +- `Chris Morgan ` +- `Chris Wong ` +- `Christopher Chambers ` +- `Clark Gaebel ` +- `Cole Reynolds ` +- `Colin Walters ` +- `Conrad Kleinespel ` +- `Corey Farwell ` +- `Dan Callahan ` +- `Dave Huseby ` +- `David Reid ` +- `Diggory Hardy ` +- `Dominic van Berkel ` +- `Dominick Allen ` +- `Don Petersen ` +- `Dzmitry Malyshau ` +- `Earl St Sauver ` +- `Eduard Burtescu ` +- `Erick Tryzelaar ` +- `Felix S. Klock II ` +- `Florian Hahn ` +- `Florian Hartwig ` +- `Franziska Hinkelmann ` +- `FuGangqiang ` +- `Garming Sam ` +- `Geoffrey Thomas ` +- `Geoffry Song ` +- `Gleb Kozyrev ` +- `Graydon Hoare ` +- `Guillaume Gomez ` +- `Hajime Morrita ` +- `Hech ` +- `Heejong Ahn ` +- `Hika Hibariya ` +- `Huon Wilson ` +- `Igor Strebezhev ` +- `Isaac Ge ` +- `J Bailey ` +- `Jake Goulding ` +- `James Miller ` +- `James Perry ` +- `Jan Andersson ` +- `Jan Bujak ` +- `Jan-Erik Rediger ` +- `Jannis Redmann ` +- `Jason Yeo ` +- `Johann ` +- `Johann Hofmann ` +- `Johannes Oertel ` +- `John Gallagher ` +- `John Van Enk ` +- `Jonathan S ` +- `Jordan Humphreys ` +- `Joseph Crail ` +- `Josh Triplett ` +- `Kang Seonghoon ` +- `Keegan McAllister ` +- `Kelvin Ly ` +- `Kevin Ballard ` +- `Kevin Butler ` +- `Kevin Mehall ` +- `Krzysztof Drewniak ` +- `Lee Aronson ` +- `Lee Jeffery ` +- `Liam Monahan ` +- `Liigo Zhuang ` +- `Luke Gallagher ` +- `Luqman Aden ` +- `Manish Goregaokar ` +- `Manuel Hoffmann ` +- `Marin Atanasov Nikolov ` +- `Mark Mossberg ` +- `Marvin Löbel ` +- `Mathieu Rochette ` +- `Mathijs van de Nes ` +- `Matt Brubeck ` +- `Michael Alexander ` +- `Michael Macias ` +- `Michael Park ` +- `Michael Rosenberg <42micro@gmail.com>` +- `Michael Sproul ` +- `Michael Woerister ` +- `Michael Wu ` +- `Michał Czardybon ` +- `Mickaël Salaün ` +- `Mike Boutin ` +- `Mike Sampson ` +- `Ms2ger ` +- `Nelo Onyiah ` +- `Nicholas ` +- `Nicholas Mazzuca ` +- `Nick Cameron ` +- `Nick Hamann ` +- `Nick Platt ` +- `Niko Matsakis ` +- `Oak ` +- `Oliver Schneider ` +- `P1start ` +- `Pascal Hertleif ` +- `Paul Banks ` +- `Paul Faria ` +- `Paul Quint ` +- `Pete Hunt ` +- `Peter Marheine ` +- `Phil Dawes ` +- `Philip Munksgaard ` +- `Piotr Czarnecki ` +- `Piotr Szotkowski ` +- `Poga Po ` +- `Przemysław Wesołek ` +- `Ralph Giles ` +- `Raphael Speyer ` +- `Remi Rampin ` +- `Ricardo Martins ` +- `Richo Healey ` +- `Rob Young ` +- `Robin Kruppe ` +- `Robin Stocker ` +- `Rory O’Kane ` +- `Ruud van Asseldonk ` +- `Ryan Prichard ` +- `Scott Olson ` +- `Sean Bowe ` +- `Sean McArthur ` +- `Sean Patrick Santos ` +- `Seo Sanghyeon ` +- `Shmuale Mark ` +- `Simon Kern ` +- `Simon Sapin ` +- `Simonas Kazlauskas ` +- `Sindre Johansen ` +- `Skyler ` +- `Steve Klabnik ` +- `Steven Allen ` +- `Swaroop C H ` +- `Sébastien Marie ` +- `Tamir Duberstein ` +- `Tero Hänninen ` +- `Theo Belaire ` +- `Theo Belaire ` +- `Thiago Carvalho ` +- `Thomas Jespersen ` +- `Tibor Benke ` +- `Tim Cuthbertson ` +- `Tincan ` +- `Ting-Yu Lin ` +- `Tobias Bucher ` +- `Toni Cárdenas ` +- `Tshepang Lekhonkhobe ` +- `Ulrik Sverdrup ` +- `Vadim Chugunov ` +- `Vadim Petrochenkov ` +- `Valerii Hiora ` +- `Wangshan Lu ` +- `Wei-Ming Yang ` +- `Will ` +- `Will Hipschman ` +- `Wojciech Ogrodowczyk ` +- `Xue Fuqiao ` +- `Xuefeng Wu ` +- `York Xiang ` +- `Young Wu ` +- `bcoopers ` +- `critiqjo ` +- `diwic ` +- `fenduru ` +- `gareins ` +- `github-monoculture ` +- `inrustwetrust ` +- `jooert ` +- `kgv ` +- `klutzy ` +- `kwantam ` +- `leunggamciu ` +- `mdinger ` +- `nwin ` +- `pez ` +- `robertfoss ` +- `rundrop1 ` +- `sinkuu ` +- `tynopex ` +- `Łukasz Niemier ` +- `らいどっと ` + +[stable]: http://blog.rust-lang.org/2014/10/30/Stability.html +[train]: http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html +[traits]: http://blog.rust-lang.org/2015/05/11/traits.html +[rfcs]: https://github.com/rust-lang/rfcs/blob/master/README.md +[1068]: https://github.com/rust-lang/rfcs/pull/1068 +[contributing]: https://github.com/rust-lang/rust/blob/master/CONTRIBUTING.md +[hb]: http://en.wikipedia.org/wiki/Heisenbug +[priorities]: http://internals.rust-lang.org/t/priorities-after-1-0/1901 +[crates.io]: https://crates.io/ +[cargo]: http://blog.rust-lang.org/2014/11/20/Cargo.html +[relnotes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-may-2015 +[caveats]: ??? +[book]: http://doc.rust-lang.org/1.0.0-beta.5/book/getting-started.html +[ffi]: http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywhere.html +[AUTHORS]: https://github.com/rust-lang/rust/blob/master/AUTHORS.txt +[23606]: https://github.com/rust-lang/rust/pull/23606/ +[1044]: https://github.com/rust-lang/rfcs/pull/1044 +[24965]: https://github.com/rust-lang/rust/pull/24965 +[24615]: https://github.com/rust-lang/rust/pull/24615 +[25323]: https://github.com/rust-lang/rust/pull/25323 From 5601686974d0cea6d9169df32fbacaae0fbc0e7b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 09:41:54 -0700 Subject: [PATCH 156/386] mention ereader --- _posts/2015-05-15-Rust-1.0.md | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index e8203f89c..707dfd290 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -12,7 +12,9 @@ safety guarantees**. Better yet, it achieves these goals without requiring a garbage collector or runtime, making it possible to [use Rust libraries as a "drop-in replacement" for C][ffi]. If you'd like to experiment with Rust, the -["Getting Started" section of the Rust book][book] is your best bet. +["Getting Started" section of the Rust book][book] is your best bet +(if you prefer to use an e-reader, Pascal Hertleif maintains +[unofficial ebook vesions][ebook] as well). What makes Rust different from other languages is its type system, which represents a refinement and codification of "best practices" @@ -69,7 +71,7 @@ Since we [announced cargo and crates.io][cargo] approximately six months ago, the number of packages has been growing steadily. Nonetheless, it's still early days, and there are still lots of great packages yet to be written. If you're interested in building -a libary that will take the Rust world by storm, there's no time like +a library that will take the Rust world by storm, there's no time like the present! ### Open Source and Open Governance @@ -326,3 +328,4 @@ whom contributed changes since our previous release (the [24965]: https://github.com/rust-lang/rust/pull/24965 [24615]: https://github.com/rust-lang/rust/pull/24615 [25323]: https://github.com/rust-lang/rust/pull/25323 +[ebook]: http://killercup.github.io/trpl-ebook/ From 083744838ca741ca04d541ffac86b27d4251b00f Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 09:54:14 -0700 Subject: [PATCH 157/386] Nits from bstrie and others --- _posts/2015-05-15-Rust-1.0.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index 707dfd290..39abe84e0 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -14,7 +14,7 @@ requiring a garbage collector or runtime, making it possible to like to experiment with Rust, the ["Getting Started" section of the Rust book][book] is your best bet (if you prefer to use an e-reader, Pascal Hertleif maintains -[unofficial ebook vesions][ebook] as well). +[unofficial e-book versions][ebook] as well). What makes Rust different from other languages is its type system, which represents a refinement and codification of "best practices" @@ -31,8 +31,8 @@ The current Rust language is the result of a lot of iteration and experimentation. The process has worked out well for us: Rust today is both simpler and more powerful than we originally thought would be possible. But all that experimentation also made it difficult to -maintain a Rust project, since the language and standard library were -constantly changing. +maintain projects written in Rust, since the language and standard +library were constantly changing. **The 1.0 release marks the end of that churn.** This release is the official beginning of our [commitment to stability][stable], and as @@ -42,7 +42,7 @@ of scope (some [caveats] apply, such as compiler bugs). That said, releasing 1.0 doesn't mean that the Rust language is "done". We have many [improvements in store][priorities]. In fact, the -Nightly builds of Rust already demonstrates [improvements to][24965] +Nightly builds of Rust already demonstrate [improvements to][24965] [compile][24615] [times][25323] (with more to come) and includes work on new APIs and language features, like [`std::fs`][1044] and [associated constants][23606]. @@ -50,9 +50,9 @@ on new APIs and language features, like [`std::fs`][1044] and To help ensure that compiler and language improvements make their way out into the ecosystem at large as quickly as possible, we've adopted a [train-based][train] release model. This means that we'll be issuing -regular releases every six weeks, just like evergreen browsers. **To -kick off that process, we are also releasing Rust 1.1 beta today, -simultaneously with Rust 1.0.** +regular releases every six weeks, just like the Firefox and Chrome web +browsers. **To kick off that process, we are also releasing Rust 1.1 +beta today, simultaneously with Rust 1.0.** ### Cargo and crates.io @@ -80,7 +80,7 @@ Rust has been an open-source project from the start. Over the last few years, we've been constantly looking for ways to make our governance more open and community driven. Since we introduced the [RFC process][rfcs] a little over a year ago, all major decisions -about Rust are written up and discussed in the open in the form of a +about Rust are written up and discussed in the open in the form of an RFC. Recently, we adopted a [new governance model][1068], which establishes a set of subteams, each responsible for RFCs in one particular area. If you'd like help shape the future of Rust, we From 986807d3de5d550ce4cc8d8ac855d52c1373e08b Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 10:00:51 -0700 Subject: [PATCH 158/386] Fix link --- _posts/2015-05-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index 39abe84e0..b3e024ab5 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -319,7 +319,7 @@ whom contributed changes since our previous release (the [crates.io]: https://crates.io/ [cargo]: http://blog.rust-lang.org/2014/11/20/Cargo.html [relnotes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-may-2015 -[caveats]: ??? +[caveats]: https://github.com/rust-lang/rfcs/pull/1122 [book]: http://doc.rust-lang.org/1.0.0-beta.5/book/getting-started.html [ffi]: http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywhere.html [AUTHORS]: https://github.com/rust-lang/rust/blob/master/AUTHORS.txt From 02e4dde6c9edf4a70c151ab6f154078b520a0dcd Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 10:04:27 -0700 Subject: [PATCH 159/386] Link to library semver --- _posts/2015-05-15-Rust-1.0.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index b3e024ab5..db8dc6247 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -38,7 +38,7 @@ library were constantly changing. official beginning of our [commitment to stability][stable], and as such it offers a firm foundation for building applications and libraries. From this point forward, breaking changes are largely out -of scope (some [caveats] apply, such as compiler bugs). +of scope (some [minor] [caveats] apply, such as compiler bugs). That said, releasing 1.0 doesn't mean that the Rust language is "done". We have many [improvements in store][priorities]. In fact, the @@ -329,3 +329,4 @@ whom contributed changes since our previous release (the [24615]: https://github.com/rust-lang/rust/pull/24615 [25323]: https://github.com/rust-lang/rust/pull/25323 [ebook]: http://killercup.github.io/trpl-ebook/ +[minor]: https://github.com/rust-lang/rfcs/pull/1105 From bac3eb9bcda24c1a96d4c209f98181c7cb728c88 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Fri, 15 May 2015 10:05:44 -0700 Subject: [PATCH 160/386] make it look better --- _posts/2015-05-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index db8dc6247..b968b1213 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -38,7 +38,7 @@ library were constantly changing. official beginning of our [commitment to stability][stable], and as such it offers a firm foundation for building applications and libraries. From this point forward, breaking changes are largely out -of scope (some [minor] [caveats] apply, such as compiler bugs). +of scope (some [minor][minor] [caveats] apply, such as compiler bugs). That said, releasing 1.0 doesn't mean that the Rust language is "done". We have many [improvements in store][priorities]. In fact, the From 3c9ce6209b251aaa7749d81134012dc2174d52a0 Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 15 May 2015 13:36:02 -0400 Subject: [PATCH 161/386] In 1.0 Release post, link to 1.0.0 version of book instead of beta --- _posts/2015-05-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index b968b1213..6f738bab4 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -320,7 +320,7 @@ whom contributed changes since our previous release (the [cargo]: http://blog.rust-lang.org/2014/11/20/Cargo.html [relnotes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-100-may-2015 [caveats]: https://github.com/rust-lang/rfcs/pull/1122 -[book]: http://doc.rust-lang.org/1.0.0-beta.5/book/getting-started.html +[book]: http://doc.rust-lang.org/1.0.0/book/getting-started.html [ffi]: http://blog.rust-lang.org/2015/04/24/Rust-Once-Run-Everywhere.html [AUTHORS]: https://github.com/rust-lang/rust/blob/master/AUTHORS.txt [23606]: https://github.com/rust-lang/rust/pull/23606/ From 455ce3c1ac5c62790da24cf1e4c06f62c6652a89 Mon Sep 17 00:00:00 2001 From: Paul Daniel Faria Date: Wed, 20 May 2015 14:07:44 -0400 Subject: [PATCH 162/386] Replaced private email with github email The current email is my work email, and I've seen spam coming in through this. I'm switching it to my github private email --- _posts/2015-05-15-Rust-1.0.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index 6f738bab4..81d457c6b 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -224,7 +224,7 @@ whom contributed changes since our previous release (the - `P1start ` - `Pascal Hertleif ` - `Paul Banks ` -- `Paul Faria ` +- `Paul Faria ` - `Paul Quint ` - `Pete Hunt ` - `Peter Marheine ` From a4a73f04c8602abcf92e73c7918ae1f337c9daac Mon Sep 17 00:00:00 2001 From: "Felix S. Klock II" Date: Mon, 25 May 2015 13:47:47 +0200 Subject: [PATCH 163/386] By popular demand strip email addresses from 1.0 blog post. --- _posts/2015-05-15-Rust-1.0.md | 430 +++++++++++++++++----------------- 1 file changed, 215 insertions(+), 215 deletions(-) diff --git a/_posts/2015-05-15-Rust-1.0.md b/_posts/2015-05-15-Rust-1.0.md index 81d457c6b..4601d2f93 100644 --- a/_posts/2015-05-15-Rust-1.0.md +++ b/_posts/2015-05-15-Rust-1.0.md @@ -92,221 +92,221 @@ We'd like to give a special thank you to the following people, each of whom contributed changes since our previous release (the [complete list of contributors][AUTHORS] is here): -- `Aaron Gallagher <_@habnab.it>` -- `Aaron Turon ` -- `Abhishek Chanda ` -- `Adolfo Ochagavía ` -- `Alex Burka ` -- `Alex Crichton ` -- `Alex Quach ` -- `Alexander Polakov ` -- `Andrea Canciani ` -- `Andreas Martens ` -- `Andreas Tolfsen ` -- `Andrei Oprea ` -- `Andrew Paseltiner ` -- `Andrew Seidl ` -- `Andrew Straw ` -- `Andrzej Janik ` -- `Aram Visser ` -- `Ariel Ben-Yehuda ` -- `Augusto Hack ` -- `Avdi Grimm ` -- `Barosl Lee ` -- `Ben Ashford ` -- `Ben Gesoff ` -- `Björn Steinbrink ` -- `Brad King ` -- `Brendan Graetz ` -- `Brett Cannon ` -- `Brian Anderson ` -- `Brian Campbell ` -- `Carlos Galarza ` -- `Carol (Nichols || Goulding) ` -- `Carol Nichols ` -- `Chris Morgan ` -- `Chris Wong ` -- `Christopher Chambers ` -- `Clark Gaebel ` -- `Cole Reynolds ` -- `Colin Walters ` -- `Conrad Kleinespel ` -- `Corey Farwell ` -- `Dan Callahan ` -- `Dave Huseby ` -- `David Reid ` -- `Diggory Hardy ` -- `Dominic van Berkel ` -- `Dominick Allen ` -- `Don Petersen ` -- `Dzmitry Malyshau ` -- `Earl St Sauver ` -- `Eduard Burtescu ` -- `Erick Tryzelaar ` -- `Felix S. Klock II ` -- `Florian Hahn ` -- `Florian Hartwig ` -- `Franziska Hinkelmann ` -- `FuGangqiang ` -- `Garming Sam ` -- `Geoffrey Thomas ` -- `Geoffry Song ` -- `Gleb Kozyrev ` -- `Graydon Hoare ` -- `Guillaume Gomez ` -- `Hajime Morrita ` -- `Hech ` -- `Heejong Ahn ` -- `Hika Hibariya ` -- `Huon Wilson ` -- `Igor Strebezhev ` -- `Isaac Ge ` -- `J Bailey ` -- `Jake Goulding ` -- `James Miller ` -- `James Perry ` -- `Jan Andersson ` -- `Jan Bujak ` -- `Jan-Erik Rediger ` -- `Jannis Redmann ` -- `Jason Yeo ` -- `Johann ` -- `Johann Hofmann ` -- `Johannes Oertel ` -- `John Gallagher ` -- `John Van Enk ` -- `Jonathan S ` -- `Jordan Humphreys ` -- `Joseph Crail ` -- `Josh Triplett ` -- `Kang Seonghoon ` -- `Keegan McAllister ` -- `Kelvin Ly ` -- `Kevin Ballard ` -- `Kevin Butler ` -- `Kevin Mehall ` -- `Krzysztof Drewniak ` -- `Lee Aronson ` -- `Lee Jeffery ` -- `Liam Monahan ` -- `Liigo Zhuang ` -- `Luke Gallagher ` -- `Luqman Aden ` -- `Manish Goregaokar ` -- `Manuel Hoffmann ` -- `Marin Atanasov Nikolov ` -- `Mark Mossberg ` -- `Marvin Löbel ` -- `Mathieu Rochette ` -- `Mathijs van de Nes ` -- `Matt Brubeck ` -- `Michael Alexander ` -- `Michael Macias ` -- `Michael Park ` -- `Michael Rosenberg <42micro@gmail.com>` -- `Michael Sproul ` -- `Michael Woerister ` -- `Michael Wu ` -- `Michał Czardybon ` -- `Mickaël Salaün ` -- `Mike Boutin ` -- `Mike Sampson ` -- `Ms2ger ` -- `Nelo Onyiah ` -- `Nicholas ` -- `Nicholas Mazzuca ` -- `Nick Cameron ` -- `Nick Hamann ` -- `Nick Platt ` -- `Niko Matsakis ` -- `Oak ` -- `Oliver Schneider ` -- `P1start ` -- `Pascal Hertleif ` -- `Paul Banks ` -- `Paul Faria ` -- `Paul Quint ` -- `Pete Hunt ` -- `Peter Marheine ` -- `Phil Dawes ` -- `Philip Munksgaard ` -- `Piotr Czarnecki ` -- `Piotr Szotkowski ` -- `Poga Po ` -- `Przemysław Wesołek ` -- `Ralph Giles ` -- `Raphael Speyer ` -- `Remi Rampin ` -- `Ricardo Martins ` -- `Richo Healey ` -- `Rob Young ` -- `Robin Kruppe ` -- `Robin Stocker ` -- `Rory O’Kane ` -- `Ruud van Asseldonk ` -- `Ryan Prichard ` -- `Scott Olson ` -- `Sean Bowe ` -- `Sean McArthur ` -- `Sean Patrick Santos ` -- `Seo Sanghyeon ` -- `Shmuale Mark ` -- `Simon Kern ` -- `Simon Sapin ` -- `Simonas Kazlauskas ` -- `Sindre Johansen ` -- `Skyler ` -- `Steve Klabnik ` -- `Steven Allen ` -- `Swaroop C H ` -- `Sébastien Marie ` -- `Tamir Duberstein ` -- `Tero Hänninen ` -- `Theo Belaire ` -- `Theo Belaire ` -- `Thiago Carvalho ` -- `Thomas Jespersen ` -- `Tibor Benke ` -- `Tim Cuthbertson ` -- `Tincan ` -- `Ting-Yu Lin ` -- `Tobias Bucher ` -- `Toni Cárdenas ` -- `Tshepang Lekhonkhobe ` -- `Ulrik Sverdrup ` -- `Vadim Chugunov ` -- `Vadim Petrochenkov ` -- `Valerii Hiora ` -- `Wangshan Lu ` -- `Wei-Ming Yang ` -- `Will ` -- `Will Hipschman ` -- `Wojciech Ogrodowczyk ` -- `Xue Fuqiao ` -- `Xuefeng Wu ` -- `York Xiang ` -- `Young Wu ` -- `bcoopers ` -- `critiqjo ` -- `diwic ` -- `fenduru ` -- `gareins ` -- `github-monoculture ` -- `inrustwetrust ` -- `jooert ` -- `kgv ` -- `klutzy ` -- `kwantam ` -- `leunggamciu ` -- `mdinger ` -- `nwin ` -- `pez ` -- `robertfoss ` -- `rundrop1 ` -- `sinkuu ` -- `tynopex ` -- `Łukasz Niemier ` -- `らいどっと ` +- `Aaron Gallagher` +- `Aaron Turon` +- `Abhishek Chanda` +- `Adolfo Ochagavía` +- `Alex Burka` +- `Alex Crichton` +- `Alex Quach` +- `Alexander Polakov` +- `Andrea Canciani` +- `Andreas Martens` +- `Andreas Tolfsen` +- `Andrei Oprea` +- `Andrew Paseltiner` +- `Andrew Seidl` +- `Andrew Straw` +- `Andrzej Janik` +- `Aram Visser` +- `Ariel Ben-Yehuda` +- `Augusto Hack` +- `Avdi Grimm` +- `Barosl Lee` +- `Ben Ashford` +- `Ben Gesoff` +- `Björn Steinbrink` +- `Brad King` +- `Brendan Graetz` +- `Brett Cannon` +- `Brian Anderson` +- `Brian Campbell` +- `Carlos Galarza` +- `Carol (Nichols || Goulding)` +- `Carol Nichols` +- `Chris Morgan` +- `Chris Wong` +- `Christopher Chambers` +- `Clark Gaebel` +- `Cole Reynolds` +- `Colin Walters` +- `Conrad Kleinespel` +- `Corey Farwell` +- `Dan Callahan` +- `Dave Huseby` +- `David Reid` +- `Diggory Hardy` +- `Dominic van Berkel` +- `Dominick Allen` +- `Don Petersen` +- `Dzmitry Malyshau` +- `Earl St Sauver` +- `Eduard Burtescu` +- `Erick Tryzelaar` +- `Felix S. Klock II` +- `Florian Hahn` +- `Florian Hartwig` +- `Franziska Hinkelmann` +- `FuGangqiang` +- `Garming Sam` +- `Geoffrey Thomas` +- `Geoffry Song` +- `Gleb Kozyrev` +- `Graydon Hoare` +- `Guillaume Gomez` +- `Hajime Morrita` +- `Hech` +- `Heejong Ahn` +- `Hika Hibariya` +- `Huon Wilson` +- `Igor Strebezhev` +- `Isaac Ge` +- `J Bailey` +- `Jake Goulding` +- `James Miller` +- `James Perry` +- `Jan Andersson` +- `Jan Bujak` +- `Jan-Erik Rediger` +- `Jannis Redmann` +- `Jason Yeo` +- `Johann` +- `Johann Hofmann` +- `Johannes Oertel` +- `John Gallagher` +- `John Van Enk` +- `Jonathan S` +- `Jordan Humphreys` +- `Joseph Crail` +- `Josh Triplett` +- `Kang Seonghoon` +- `Keegan McAllister` +- `Kelvin Ly` +- `Kevin Ballard` +- `Kevin Butler` +- `Kevin Mehall` +- `Krzysztof Drewniak` +- `Lee Aronson` +- `Lee Jeffery` +- `Liam Monahan` +- `Liigo Zhuang` +- `Luke Gallagher` +- `Luqman Aden` +- `Manish Goregaokar` +- `Manuel Hoffmann` +- `Marin Atanasov Nikolov` +- `Mark Mossberg` +- `Marvin Löbel` +- `Mathieu Rochette` +- `Mathijs van de Nes` +- `Matt Brubeck` +- `Michael Alexander` +- `Michael Macias` +- `Michael Park` +- `Michael Rosenberg` +- `Michael Sproul` +- `Michael Woerister` +- `Michael Wu` +- `Michał Czardybon` +- `Mickaël Salaün` +- `Mike Boutin` +- `Mike Sampson` +- `Ms2ger` +- `Nelo Onyiah` +- `Nicholas` +- `Nicholas Mazzuca` +- `Nick Cameron` +- `Nick Hamann` +- `Nick Platt` +- `Niko Matsakis` +- `Oak` +- `Oliver Schneider` +- `P1start` +- `Pascal Hertleif` +- `Paul Banks` +- `Paul Faria` +- `Paul Quint` +- `Pete Hunt` +- `Peter Marheine` +- `Phil Dawes` +- `Philip Munksgaard` +- `Piotr Czarnecki` +- `Piotr Szotkowski` +- `Poga Po` +- `Przemysław Wesołek` +- `Ralph Giles` +- `Raphael Speyer` +- `Remi Rampin` +- `Ricardo Martins` +- `Richo Healey` +- `Rob Young` +- `Robin Kruppe` +- `Robin Stocker` +- `Rory O’Kane` +- `Ruud van Asseldonk` +- `Ryan Prichard` +- `Scott Olson` +- `Sean Bowe` +- `Sean McArthur` +- `Sean Patrick Santos` +- `Seo Sanghyeon` +- `Shmuale Mark` +- `Simon Kern` +- `Simon Sapin` +- `Simonas Kazlauskas` +- `Sindre Johansen` +- `Skyler` +- `Steve Klabnik` +- `Steven Allen` +- `Swaroop C H` +- `Sébastien Marie` +- `Tamir Duberstein` +- `Tero Hänninen` +- `Theo Belaire` +- `Theo Belaire` +- `Thiago Carvalho` +- `Thomas Jespersen` +- `Tibor Benke` +- `Tim Cuthbertson` +- `Tincan` +- `Ting-Yu Lin` +- `Tobias Bucher` +- `Toni Cárdenas` +- `Tshepang Lekhonkhobe` +- `Ulrik Sverdrup` +- `Vadim Chugunov` +- `Vadim Petrochenkov` +- `Valerii Hiora` +- `Wangshan Lu` +- `Wei-Ming Yang` +- `Will` +- `Will Hipschman` +- `Wojciech Ogrodowczyk` +- `Xue Fuqiao` +- `Xuefeng Wu` +- `York Xiang` +- `Young Wu` +- `bcoopers` +- `critiqjo` +- `diwic` +- `fenduru` +- `gareins` +- `github-monoculture` +- `inrustwetrust` +- `jooert` +- `kgv` +- `klutzy` +- `kwantam` +- `leunggamciu` +- `mdinger` +- `nwin` +- `pez` +- `robertfoss` +- `rundrop1` +- `sinkuu` +- `tynopex` +- `Łukasz Niemier` +- `らいどっと` [stable]: http://blog.rust-lang.org/2014/10/30/Stability.html [train]: http://blog.rust-lang.org/2014/12/12/1.0-Timeline.html From 6ca9f94d981c2e11b26a0bffb38790fabb426dcd Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 25 Jun 2015 09:47:01 -0700 Subject: [PATCH 164/386] Rust 1.1 stable --- _posts/2015-06-25-Rust-1.1.md | 259 ++++++++++++++++++++++++++++++++++ 1 file changed, 259 insertions(+) create mode 100644 _posts/2015-06-25-Rust-1.1.md diff --git a/_posts/2015-06-25-Rust-1.1.md b/_posts/2015-06-25-Rust-1.1.md new file mode 100644 index 000000000..22e6d7a0e --- /dev/null +++ b/_posts/2015-06-25-Rust-1.1.md @@ -0,0 +1,259 @@ +--- +layout: post +title: "Rust 1.1 stable, the Community Subteam, and RustCamp" +author: The Rust Core Team +--- + +We're happy to announce the completion of the first release cycle after Rust +1.0: today we are [releasing][install] Rust 1.1 stable, as well as 1.2 beta. + +Read on for details the releases, as well as some exciting new developments +within the Rust community. + +[install]: http://www.rust-lang.org/install.html + +### What's in 1.1 Stable + +One of the highest priorities for Rust after its 1.0 has been improving compile +times. Thanks to the hard work of a number of contributors, Rust 1.1 stable +provides a **32% improvement** in compilation time over Rust 1.0 (as measured by +bootstrapping). + +Another major focus has been improving error messages throughout the +compiler. Again thanks to a number of contributors, a large portion of compiler +errors now include extended explanations accessible using the `--explain` flag. + +Beyond these improvements, the 1.1 release includes a number of important new +features: + +* *New `std::fs` APIs*. This release stabilizes a + [large set of extensions](https://github.com/rust-lang/rfcs/pull/1044) to the + filesystem APIs, making it possible, for example, to compile Cargo on stable Rust. +* *MUSL support*. It's + [now possible](https://github.com/rust-lang/rust/pull/24777) to target + [MUSL](http://www.musl-libc.org/) on Linux. Binaries built this way are + statically linked and have zero dependencies. Nightlies are on the way. +* *`cargo rustc`*. It's now possible to build a Cargo package while passing + arbitrary flags to the final `rustc` invocation. + +More detail is available in the [release notes][rn]. + +[rn]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-110-june-2015 + +### What's in 1.2 Beta + +Performance improvements didn't stop with 1.1 stable. Benchmark compilations are +showing an **additional 30%** improvement from 1.1 stable to 1.2 beta; Cargo's +main crate compiles 18% faster. + +In addition, [parallel codegen](https://github.com/rust-lang/rust/pull/26018) is +working again, and can substantially speed up large builds in debug mode; it +gets another 33% speedup on bootstrapping on a 4 core machine. It's not yet on +by default, but will be in the near future. + +Cargo has also seen some performance improvements, including a 10x speedup on +large "no-op" builds (from 5s to 0.5s on Servo), and shared target directories +that cache dependencies across multiple packages. + +In addition to all of this, 1.2 beta includes our first support for MSVC +(Microsoft Visual C): the compiler is able to bootstrap, and we have preliminary +nightlies targeting the platform. This is a big step for our Windows support, +making it much easier to link Rust code against code built using the native +toolchain. Unwinding is not yet available -- code aborts on panic -- but the +implementation is otherwise complete, and all rust-lang crates are now testing +on MSVC as a first-tier platform. + +Rust 1.2 stable will be released six weeks from now, together with 1.3 beta. + +### Community news + +In addition to the above technical work, there's some exciting news within the +Rust community. + +In the past few weeks, we've [formed a new subteam][community] explicitly +devoted to supporting the Rust community. The team will have a number of +responsibilities, including aggregating resources for meetups and other events, +supporting diversity in the community through leadership in outreach, policies, +and awareness-raising, and working with our early production users and the core +team to help guide prioritization. + +In addition, we'll soon be holding the first official Rust conference: +[RustCamp](http://rustcamp.com/), on August 1, 2015, in Berkeley, CA, USA. We've +received a number of excellent talk submissions, and are expecting a great +program. + +[community]: https://internals.rust-lang.org/t/announcing-the-community-subteam/2248 + +### Contributors to 1.1 + +As with every release, 1.1 stable is the result of work from an amazing and +active community. Thanks to the 168 contributors to this release: + +- Aaron Gallagher +- Aaron Turon +- Abhishek Chanda +- Adolfo Ochagavía +- Alex Burka +- Alex Crichton +- Alexander Polakov +- Alexis Beingessner +- Andreas Tolfsen +- Andrei Oprea +- Andrew Paseltiner +- Andrew Straw +- Andrzej Janik +- Aram Visser +- Ariel Ben-Yehuda +- Avdi Grimm +- Barosl Lee +- Ben Gesoff +- Björn Steinbrink +- Brad King +- Brendan Graetz +- Brian Anderson +- Brian Campbell +- Carol Nichols +- Chris Morgan +- Chris Wong +- Clark Gaebel +- Cole Reynolds +- Colin Walters +- Conrad Kleinespel +- Corey Farwell +- David Reid +- Diggory Hardy +- Dominic van Berkel +- Don Petersen +- Eduard Burtescu +- Eli Friedman +- Erick Tryzelaar +- Felix S. Klock II +- Florian Hahn +- Florian Hartwig +- Franziska Hinkelmann +- FuGangqiang +- Garming Sam +- Geoffrey Thomas +- Geoffry Song +- Graydon Hoare +- Guillaume Gomez +- Hech +- Heejong Ahn +- Hika Hibariya +- Huon Wilson +- Isaac Ge +- J Bailey +- Jake Goulding +- James Perry +- Jan Andersson +- Jan Bujak +- Jan-Erik Rediger +- Jannis Redmann +- Jason Yeo +- Johann +- Johann Hofmann +- Johannes Oertel +- John Gallagher +- John Van Enk +- Jordan Humphreys +- Joseph Crail +- Kang Seonghoon +- Kelvin Ly +- Kevin Ballard +- Kevin Mehall +- Krzysztof Drewniak +- Lee Aronson +- Lee Jeffery +- Liigo Zhuang +- Luke Gallagher +- Luqman Aden +- Manish Goregaokar +- Marin Atanasov Nikolov +- Mathieu Rochette +- Mathijs van de Nes +- Matt Brubeck +- Michael Park +- Michael Rosenberg +- Michael Sproul +- Michael Wu +- Michał Czardybon +- Mike Boutin +- Mike Sampson +- Ms2ger +- Nelo Onyiah +- Nicholas +- Nicholas Mazzuca +- Nick Cameron +- Nick Hamann +- Nick Platt +- Niko Matsakis +- Oliver Schneider +- P1start +- Pascal Hertleif +- Paul Banks +- Paul Faria +- Paul Quint +- Pete Hunt +- Peter Marheine +- Philip Munksgaard +- Piotr Czarnecki +- Poga Po +- Przemysław Wesołek +- Ralph Giles +- Raphael Speyer +- Ricardo Martins +- Richo Healey +- Rob Young +- Robin Kruppe +- Robin Stocker +- Rory O’Kane +- Ruud van Asseldonk +- Ryan Prichard +- Sean Bowe +- Sean McArthur +- Sean Patrick Santos +- Shmuale Mark +- Simon Kern +- Simon Sapin +- Simonas Kazlauskas +- Sindre Johansen +- Skyler +- Steve Klabnik +- Steven Allen +- Steven Fackler +- Swaroop C H +- Sébastien Marie +- Tamir Duberstein +- Theo Belaire +- Thomas Jespersen +- Tincan +- Ting-Yu Lin +- Tobias Bucher +- Toni Cárdenas +- Tshepang Lekhonkhobe +- Ulrik Sverdrup +- Vadim Chugunov +- Valerii Hiora +- Wangshan Lu +- Wei-Ming Yang +- Wojciech Ogrodowczyk +- Xuefeng Wu +- York Xiang +- Young Wu +- bors +- critiqjo +- diwic +- gareins +- inrustwetrust +- jooert +- klutzy +- kwantam +- leunggamciu +- mdinger +- nwin +- parir +- pez +- robertfoss +- sinkuu +- tynopex +- らいどっと From a9f3dbe646a0c0667a1604291435a019ce2322ba Mon Sep 17 00:00:00 2001 From: Elaine Date: Thu, 25 Jun 2015 14:23:55 -0400 Subject: [PATCH 165/386] musl is not stylized as MUSL --- _posts/2015-06-25-Rust-1.1.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-06-25-Rust-1.1.md b/_posts/2015-06-25-Rust-1.1.md index 22e6d7a0e..721849b49 100644 --- a/_posts/2015-06-25-Rust-1.1.md +++ b/_posts/2015-06-25-Rust-1.1.md @@ -29,9 +29,9 @@ features: * *New `std::fs` APIs*. This release stabilizes a [large set of extensions](https://github.com/rust-lang/rfcs/pull/1044) to the filesystem APIs, making it possible, for example, to compile Cargo on stable Rust. -* *MUSL support*. It's +* *musl support*. It's [now possible](https://github.com/rust-lang/rust/pull/24777) to target - [MUSL](http://www.musl-libc.org/) on Linux. Binaries built this way are + [musl](http://www.musl-libc.org/) on Linux. Binaries built this way are statically linked and have zero dependencies. Nightlies are on the way. * *`cargo rustc`*. It's now possible to build a Cargo package while passing arbitrary flags to the final `rustc` invocation. From 783529d8d1ca7d9cced596ada1ea09f3b97b3f43 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Tue, 4 Aug 2015 14:42:16 -0700 Subject: [PATCH 166/386] Rust 1.2 announcement --- _posts/2015-08-06-Rust-1.2.md | 272 ++++++++++++++++++++++++++++++++++ 1 file changed, 272 insertions(+) create mode 100644 _posts/2015-08-06-Rust-1.2.md diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md new file mode 100644 index 000000000..94cc9ed5a --- /dev/null +++ b/_posts/2015-08-06-Rust-1.2.md @@ -0,0 +1,272 @@ +--- +layout: post +title: "Announcing Rust 1.2" +author: The Rust Core Team +--- + +Today marks the end of another Rust release cycle: we are [releasing][install] +Rust 1.2 stable and 1.3 beta! + +[install]: http://www.rust-lang.org/install.html + +### What's in 1.2 stable + +As we +[previously announced](http://blog.rust-lang.org/2015/06/25/Rust-1.1.html), Rust +1.2 comes with two major performance improvements for the compiler: + +- **An across-the-board improvement** reaching 30% on some benchmarks. Compiling + Cargo's main crate is now 18% faster. + +- **Parallel codegen** is + [now working](https://github.com/rust-lang/rust/pull/26018), and produces a + 33% speedup when bootstrapping on a 4 core machine. Parallel codegen is + particularly useful for debug builds, since it prevents some optimizations; + but it can also be used with optimizations as an effective `-O1` flag. It can + be activated by passing `-C codegen-units=N` to `rustc`, where `N` is the + desired number of threads. + +Cargo's performance has also improved dramatically: + +- Builds that do not require any recompilation ("no-op builds") for large + projects are much faster: for Servo, build time went from 5 seconds to 0.5 + seconds. + +- Cargo now supports shared target directories that cache dependencies across + multiple packages, which results in significant build-time reduction for + complex projects. + +The 1.2 release also +[introduces support](https://github.com/rust-lang/rust/pull/25350) for the MSVC +(Microsoft Visual C) toolchain, as opposed to GNU variants. The upshot is that +Rust code is now directly linkable against code built using the native Windows +toolchain. The compiler bootstraps on MSVC, we have preliminary nightlies, and +we are testing all rust-lang crates against MSVC. Unwinding support is not yet +available (the process aborts on panic), but work is underway to land it. + +On the language side, Rust 1.2 marks the completion of the +[dynamically-sized type (DST)](http://smallcultfollowing.com/babysteps/blog/2014/01/05/dst-take-5/) +work, allowing smart pointers like `Rc` to seamless apply to arrays and trait +objects, so that `Rc<[T]>` is fully usable. This final enhancement applies to +all smart pointers in the standard library. Support for external smart pointer +types is available in nightlies, and will be stabilized soon. + +### What's in 1.3 beta + +One of the most exciting developments during the 1.3 cycle was the introduction +of the [Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/), a new book +covering "The Dark Arts of Advanced and Unsafe Rust Programming". While it's +still in its early days, this book already provides indispensable coverage of +some of Rust's more subtle aspects. + +The 1.3 cycle also saw additional focus on performance, though most wins here +are within the standard library: + +- The substring matcher now uses a + [more efficient algorithm](https://github.com/rust-lang/rust/pull/26327). +- There were + [improvements to zero filling](https://github.com/rust-lang/rust/pull/26849) + that speed up `Vec::resize` and `Read::read_to_end` +- The implementation of `Read::read_to_end` has been + [specialized for `stdin` and `File`](https://github.com/rust-lang/rust/pull/26950), + resulting in additional speedups. +- The `PartialEq` implementation on slices is now + [much faster](https://github.com/rust-lang/rust/pull/26884). + +We have also made strides in our Windows support, landing +[preliminary support for Windows XP](https://github.com/rust-lang/rust/pull/26601). While +we do not intend to treat Windows XP as a "first tier" platform, it is now +feasible to build Rust code for XP as long as you avoid certain parts of the +standard library. + +On the Cargo front, we have landed support for +[lint capping](https://github.com/rust-lang/rust/pull/27260) as specified by an +[earlier RFC](https://github.com/rust-lang/rfcs/pull/1193). The idea is that +lints in your dependencies should not affect your ability to compile cleanly, +which in turn makes it easier to tweak the way lints work without undue hassle +in the ecosystem. + +### Contributors to 1.2 + +The 1.2 stable release represents the hard work of 180 fine folks: + +- Aaron Turon +- Abhishek Chanda +- Adolfo Ochagavía +- Aidan Hobson Sayers +- Akshay Chiwhane +- Alex Burka +- Alex Crichton +- Alex Stokes +- Alexander Artemenko +- Alexis Beingessner +- Andrea Canciani +- Andrew Foote +- Andrew Kensler +- Andrew Straw +- Ariel Ben-Yehuda +- Austin Hellyer +- Barosl Lee +- Ben Striegel +- Björn Steinbrink +- Brian Anderson +- Brian Campbell +- Brian Leibig +- Brian Quinlan +- Carol (Nichols || Goulding) +- Chris Hellmuth +- Christian Stadelmann +- Chuck Bassett +- Corey Farwell +- Cornel Punga +- Cruz Julian Bishop +- Dave Huseby +- David Campbell +- David Stygstra +- David Voit +- Eduard Bopp +- Eduard Burtescu +- Eli Friedman +- Emilio Cobos Álvarez +- Emily Dunham +- Eric Ye +- Erik Michaels-Ober +- Falco Hirschenberger +- Felix S. Klock II +- FuGangqiang +- Geoffrey Thomas +- Gleb Kozyrev +- Guillaume Gomez +- Gulshan Singh +- Heejong Ahn +- Huachao Huang +- Huon Wilson +- Ivan Ukhov +- Iven Hsu +- Jake Goulding +- Jake Hickey +- James Miller +- Jared Roesch +- Jeremy Schlatter +- Jexell +- Jim Blandy +- Johann Tuffe +- Johannes Hoff +- Johannes Oertel +- John Hodge +- Jonathan Reem +- Joshua Landau +- Kevin Ballard +- Kubilay Kocak +- Lee Jeffery +- Leo Correa +- Liigo Zhuang +- Lorenz +- Luca Bruno +- Luqman Aden +- Manish Goregaokar +- Marcel Müller +- Marcus Klaas +- Marin Atanasov Nikolov +- Markus Westerlind +- Martin Pool +- Marvin Löbel +- Matej Lach +- Mathieu David +- Matt Brubeck +- Matthew Astley +- Max Jacobson +- Maximilian Haack +- Michael Layzell +- Michael Macias +- Michael Rosenberg +- Michael Sproul +- Michael Woerister +- Mihnea Dobrescu-Balaur +- Mikhail Zabaluev +- Mohammed Attia +- Ms2ger +- Murarth +- Mário Feroldi +- Nathan Long +- Nathaniel Theis +- Nick Cameron +- Nick Desaulniers +- Nick Fitzgerald +- Nick Hamann +- Nick Howell +- Niko Matsakis +- Nils Liberg +- OlegTsyba +- Oliver 'ker' Schneider +- Oliver Schneider +- P1start +- Parker Moore +- Pascal Hertleif +- Paul Faria +- Paul Oliver +- Peer Aramillo Irizar +- Peter Atashian +- Peter Elmers +- Philip Munksgaard +- Ralph Giles +- Rein Henrichs +- Ricardo Martins +- Richo Healey +- Ricky Taylor +- Russell Johnston +- Russell McClellan +- Ryan Pendleton +- Ryman +- Rémi Audebert +- Sae-bom Kim +- Sean Collins +- Sean Gillespie +- Sean Patrick Santos +- Seo Sanghyeon +- Simon Sapin +- Simonas Kazlauskas +- Steve Gury +- Steve Klabnik +- Steven Allen +- Steven Fackler +- Steven Walter +- Sébastien Marie +- Tamir Duberstein +- Thomas Karpiniec +- Tim Ringenbach +- Tshepang Lekhonkhobe +- Ulrik Sverdrup +- Vadim Petrochenkov +- Wei-Ming Yang +- Wesley Wiser +- Wilfred Hughes +- Will Andrews +- Will Engler +- Xuefeng Wu +- XuefengWu +- Yongqian Li +- York Xiang +- Z1 +- ben fleis +- benaryorg +- bluss +- bors +- clatour +- diwic +- dmgawel +- econoplas +- frankamp +- funkill +- inrustwetrust +- joliv +- klutzy +- marcell +- mdinger +- olombard +- peferron +- ray glover +- saml +- simplex +- sumito3478 +- webmobster From 392b8383b41fb321cf5e6eb4a2eb1afeea88aa9e Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 09:04:53 -0700 Subject: [PATCH 167/386] Clarify XP situation --- _posts/2015-08-06-Rust-1.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index 94cc9ed5a..bcb22fef1 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -74,7 +74,7 @@ are within the standard library: [much faster](https://github.com/rust-lang/rust/pull/26884). We have also made strides in our Windows support, landing -[preliminary support for Windows XP](https://github.com/rust-lang/rust/pull/26601). While +[preliminary support for targeting Windows XP](https://github.com/rust-lang/rust/pull/26601). While we do not intend to treat Windows XP as a "first tier" platform, it is now feasible to build Rust code for XP as long as you avoid certain parts of the standard library. From 5ba236c44d0fff4eaff3efbe9b88167025e53f5e Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 09:15:32 -0700 Subject: [PATCH 168/386] Add excitement --- _posts/2015-08-06-Rust-1.2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index bcb22fef1..7481e7bcd 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -4,8 +4,8 @@ title: "Announcing Rust 1.2" author: The Rust Core Team --- -Today marks the end of another Rust release cycle: we are [releasing][install] -Rust 1.2 stable and 1.3 beta! +Today marks the [completion][install] of the Rust 1.2 stable and 1.3 beta +release cycles! Read on for the details. [install]: http://www.rust-lang.org/install.html From f9cc484dae1a3f5fe68534fbe723ef5c1eeaa7d5 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 09:31:03 -0700 Subject: [PATCH 169/386] Reference release notes --- _posts/2015-08-06-Rust-1.2.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index 7481e7bcd..d79a0852b 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -5,9 +5,11 @@ author: The Rust Core Team --- Today marks the [completion][install] of the Rust 1.2 stable and 1.3 beta -release cycles! Read on for the details. +release cycles! Read on for the highlight, or check the [release notes][notes] +for more detail. [install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-120-august-2015 ### What's in 1.2 stable From 6937d13860090b208d27a7802f191f499f1b1d89 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 10:01:46 -0700 Subject: [PATCH 170/386] More detailed benchmark data --- _posts/2015-08-06-Rust-1.2.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index d79a0852b..30c9abdb1 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -17,8 +17,12 @@ As we [previously announced](http://blog.rust-lang.org/2015/06/25/Rust-1.1.html), Rust 1.2 comes with two major performance improvements for the compiler: -- **An across-the-board improvement** reaching 30% on some benchmarks. Compiling - Cargo's main crate is now 18% faster. +- **An across-the-board improvement** to real-world compiler + performance. Representative crates include hyper (compiles 1.16x faster), + html5ever (1.62x faster), regex (1.32x faster) and rust-encoding (1.35x) + You can explore some of this performance + data at Nick Cameron's [preliminary tracking site](http://www.ncameron.org/perf-rustc/), using dates + 2015-05-15 to 2015-06-25. - **Parallel codegen** is [now working](https://github.com/rust-lang/rust/pull/26018), and produces a From 2901011933bd2b9fe2960ab8f885f5c688995f6c Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 10:06:53 -0700 Subject: [PATCH 171/386] Add links --- _posts/2015-08-06-Rust-1.2.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index 30c9abdb1..4c61f2a05 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -18,10 +18,11 @@ As we 1.2 comes with two major performance improvements for the compiler: - **An across-the-board improvement** to real-world compiler - performance. Representative crates include hyper (compiles 1.16x faster), - html5ever (1.62x faster), regex (1.32x faster) and rust-encoding (1.35x) - You can explore some of this performance - data at Nick Cameron's [preliminary tracking site](http://www.ncameron.org/perf-rustc/), using dates + performance. Representative crates include [hyper][hyper] (compiles 1.16x + faster), [html5ever][html5ever] (1.62x faster), [regex][regex] (1.32x faster) + and [rust-encoding][rust-encoding] (1.35x) You can explore some of this + performance data at Nick Cameron's + [preliminary tracking site](http://www.ncameron.org/perf-rustc/), using dates 2015-05-15 to 2015-06-25. - **Parallel codegen** is @@ -57,6 +58,11 @@ objects, so that `Rc<[T]>` is fully usable. This final enhancement applies to all smart pointers in the standard library. Support for external smart pointer types is available in nightlies, and will be stabilized soon. +[hyper]: https://crates.io/crates/hyper +[html5ever]: https://crates.io/crates/html5ever +[regex]: https://crates.io/crates/regex +[rust-encoding]: https://crates.io/crates/encoding + ### What's in 1.3 beta One of the most exciting developments during the 1.3 cycle was the introduction From 11822a759c71ce9bd7ec6f78cf17fbdf10eec1af Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 10:07:45 -0700 Subject: [PATCH 172/386] Add missing period --- _posts/2015-08-06-Rust-1.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index 4c61f2a05..09852ef0f 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -20,7 +20,7 @@ As we - **An across-the-board improvement** to real-world compiler performance. Representative crates include [hyper][hyper] (compiles 1.16x faster), [html5ever][html5ever] (1.62x faster), [regex][regex] (1.32x faster) - and [rust-encoding][rust-encoding] (1.35x) You can explore some of this + and [rust-encoding][rust-encoding] (1.35x). You can explore some of this performance data at Nick Cameron's [preliminary tracking site](http://www.ncameron.org/perf-rustc/), using dates 2015-05-15 to 2015-06-25. From a99cdd17b1ed62e0936e0a47f6c9afe3c6ddf124 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 10:08:29 -0700 Subject: [PATCH 173/386] Add missing 'faster' --- _posts/2015-08-06-Rust-1.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index 09852ef0f..fb66b39ba 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -20,7 +20,7 @@ As we - **An across-the-board improvement** to real-world compiler performance. Representative crates include [hyper][hyper] (compiles 1.16x faster), [html5ever][html5ever] (1.62x faster), [regex][regex] (1.32x faster) - and [rust-encoding][rust-encoding] (1.35x). You can explore some of this + and [rust-encoding][rust-encoding] (1.35x faster). You can explore some of this performance data at Nick Cameron's [preliminary tracking site](http://www.ncameron.org/perf-rustc/), using dates 2015-05-15 to 2015-06-25. From 2b4a63c8a6325327df0723daa266d0eb233b981e Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 6 Aug 2015 10:08:59 -0700 Subject: [PATCH 174/386] Missing period --- _posts/2015-08-06-Rust-1.2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-06-Rust-1.2.md b/_posts/2015-08-06-Rust-1.2.md index fb66b39ba..3132bec74 100644 --- a/_posts/2015-08-06-Rust-1.2.md +++ b/_posts/2015-08-06-Rust-1.2.md @@ -78,7 +78,7 @@ are within the standard library: [more efficient algorithm](https://github.com/rust-lang/rust/pull/26327). - There were [improvements to zero filling](https://github.com/rust-lang/rust/pull/26849) - that speed up `Vec::resize` and `Read::read_to_end` + that speed up `Vec::resize` and `Read::read_to_end`. - The implementation of `Read::read_to_end` has been [specialized for `stdin` and `File`](https://github.com/rust-lang/rust/pull/26950), resulting in additional speedups. From 7f35376d3be68a92b10d7d1503e991482b7567c4 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 12 Aug 2015 10:21:49 -0700 Subject: [PATCH 175/386] Initial sketch: the next year of Rust --- _posts/2015-08-13-Next-year.md | 158 +++++++++++++++++++++++++++++++++ 1 file changed, 158 insertions(+) create mode 100644 _posts/2015-08-13-Next-year.md diff --git a/_posts/2015-08-13-Next-year.md b/_posts/2015-08-13-Next-year.md new file mode 100644 index 000000000..6627a533d --- /dev/null +++ b/_posts/2015-08-13-Next-year.md @@ -0,0 +1,158 @@ +--- +layout: post +title: "The next year of Rust" +author: Nicholas Matsakis and Aaron Turon +description: "Our vision for Rust in 2016." +--- + +It's now been 12 weeks since the release of Rust 1.0, and we'd like to take this +opportunity to **talk a bit about what 1.0 meant in hindsight, and where Rust is +going in the next year**. + +### The next year of Rust + +> We recently held the first-ever Rust conference, [RustCamp][rustcamp] 2015, +which sold out with 160 attendees. It was amazing to see so much of the Rust +community in person, and to see the vibe of our online spaces translate into a +friendly and approachable meatspace event. The day opened with a keynote from +Nicholas Matsakis and Aaron Turon laying out the core team's view of where we +are and where we're headed. The +[slides are available online](http://rustcamp.com/RustCampKeynote.pdf), but this +post serves as the missing soundtrack. + +[rustcamp]: http://rustcamp.com/ + +#### What 1.0 was about + +In hindsight, Rust 1.0 was about nailing down three key concerns: clarity, +stability, and community. Stability, we've discussed quite a bit in +[previous posts][deliverable]. And, of course, community has always been one of +Rust's greatest strengths. But in the year leading up to 1.0 in particular, we +introduced and refined the [RFC process][rfcs], culminating with +[subteams][subteams] to manage RFCs in each particular area. Community-wide +debate on RFCs was indispensable for delivering a quality 1.0 release. + +All of this refinement prior to 1.0 was in service of clarifying what Rust +represents: + +- Memory safety without garbage collection +- [Concurrency without data races][fearless] +- [Abstraction without overhead][traits] +- [Stability without stagnation][deliverable] + +Altogether, **Rust is exciting because it is empowering: you can hack without +fear**. And you can do so in contexts you might not have before, dropping down +from Ruby or Python, making your first foray into systems programming. + +That's Rust 1.0; what's next? + +[deliverable]: http://blog.rust-lang.org/2014/10/30/Stability.html +[rfcs]: https://github.com/rust-lang/rfcs#when-you-need-to-follow-this-process +[subteams]: https://github.com/rust-lang/rfcs/pull/1068 +[fearless]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html +[traits]: http://blog.rust-lang.org/2015/05/11/traits.html + +#### Where we go from here + +After much discussion within the core team and with the broader community, we've +identified a number of improvements we'd like to make over the course of the +next or so, falling into three broad categories: + +- Doubling down on infrastructure; +- Zeroing in on gaps in key features; +- Branching out into new places to use Rust. + +Let's look at some of the biggest plans in each of these categories. + +#### Doubling down: infrastructure investments + +**Crater**. + +**Incremental compilation**. [MIR][mir] + +[mir]: https://github.com/rust-lang/rfcs/pull/1211 + +**IDE integration**. + +#### Zeroing in: closing key gaps in our features + +**Specialization**. The idea of zero-cost abstractions breaks down into two +separate goals, as identified by Stroustrup: + +- What you don't use, you don't pay for. +- What you do use, you couldn't hand code any better. + +Rust 1.0 has essentially achieved the first goal, both in terms of language +features and the standard library. But it doesn't quite manage to achieve the +second goal. Take the following trait, for example: + +~~~~rust +pub trait Extend { + fn extend(&mut self, iterable: T) where T: IntoIterator; +} +~~~~ + +The `Extend` trait provides a nice abstraction for insert data from any kind of +iterator into a collection. But with traits today, that also means that each +collection can provide only one implementation that works for *all* iterator +types, which requires actually calling `.next()` repeatedly. In some cases, you +could hand code it better, e.g. by just calling `memcpy`. + +To close this gap, we've proposed [specialization][specialization], allowing you +to provide multiple, overlapping trait implementations as long as one is clearly +more specific than the other. Aside from giving Rust a more complete toolkit for +zero-cost abstraction, specialization also improves its story for code +reuse. See [the RFC][specialization] for more details. + +[specialization]: https://github.com/rust-lang/rfcs/pull/1210 + +**Borrow checker improvements**. The borrow checker is, in a way, the beating +heart of Rust; it's the part of the compiler that lets us achieve memory safety +without garbage collection, by catching use-after-free bugs and the like. But +occasionally, the borrower checker also "catches" non-bugs, like the following +pattern: + +~~~~rust +match map.find(&key) { + Some(...) => { ... } + None => { + map.insert(key, new_value); + } +} +~~~~ + +Code like the above snippet is perfectly fine, but the borrow checker struggles +with it today because the `map` variable is borrowed for the entire body of the +`match`, preventing it from being mutated by `insert`. We plan to address this +shortcoming soon by refactoring the borrow checker to view code in terms of +finer-grained ("non-lexical") regions -- a step made possible by the move to the +MIR mentioned above. + +**Plugins**. There are some really neat things you can do in Rust today -- if +you're willing to use the Nightly channel. For example, the [regex crate][regex] +comes with macros that, at compile time, turn regular expressions directly into +machine code to match them. Or the [rust-postgres-macros crage][postgres], which +checks at compile time for valid SQL syntax. Crates like these and others make +use of a highly-unstable compiler plugin system that currently exposes far too +many compiler internals. We plan in the next couple of months to propose a new, +robust design that closes these holes and provides good support for hygienic +macro expansion as well. + +[regex]: https://github.com/rust-lang/regex +[postgres]: https://github.com/sfackler/rust-postgres-macros + +#### Branching out: taking Rust to new places + +**Cross-compilation**. + +**Cargo install**. [RFC][cargoinstall] + +[cargoinstall]: https://github.com/rust-lang/rfcs/pull/1200 + +**Tracing hooks**. One of the most promising way of using Rust is by "embedding" +Rust code into systems written in higher-level languages like [Ruby][skylight] +or Python. This embedding is usually done by giving the Rust code a C API, and +works reasonably well when the target sports a "C friendly" memory management +scheme like reference counting or conservative GC. + +[skylight]: http://blog.skylight.io/bending-the-curve-writing-safe-fast-native-gems-with-rust/ From b86ee0ff865f8e206252e7936d3bfb6e11338b55 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 12 Aug 2015 16:58:01 -0400 Subject: [PATCH 176/386] first draft of mising sections --- _posts/2015-08-13-Next-year.md | 123 ++++++++++++++++++++++++++++----- 1 file changed, 107 insertions(+), 16 deletions(-) diff --git a/_posts/2015-08-13-Next-year.md b/_posts/2015-08-13-Next-year.md index 6627a533d..806e62035 100644 --- a/_posts/2015-08-13-Next-year.md +++ b/_posts/2015-08-13-Next-year.md @@ -66,13 +66,71 @@ Let's look at some of the biggest plans in each of these categories. #### Doubling down: infrastructure investments -**Crater**. - -**Incremental compilation**. [MIR][mir] +**Crater**. One of our big goals with Rust is that upgrades between +versions should be "hassle-free". An important part of this story is +detecting compiler bugs that cause code to stop working. Naturally, +the compiler has its own large test suite, but that is only a small +fraction of the code that's out there "in the wild". [Crater] is a +tool that aims to close that gap by testing the compiler against all +the packages found in [crates.io], giving us a much better idea +whether any code has stopped compiling recently. + +We've been using the current version of crater for some time. For +example, we regularly compare the nightly release against the latest +stable build. We also use crater to check in-progress branches and +estimate the impact of a change. + +Interestingly, we have often found that when code stops compiling, +it's not because of a bug in the compiler. Rather, it's because we +*fixed* a bug, and that code happened to be relying on the older +behavior. Even in those cases, using crater lets us improve the +experience. For example, for changes that affect a lot of projects, +we've often chosen to phase in the change gradually. In such cases, we +issue one release where users get warnings, and only start issuing +errors on the next release, giving people time to migrate their code. + +Over the next year or so, we plan to improve crater in numerous ways. +For example, we'd like to extend the coverage to other platforms (not +just linux). We'd also like to make it smoother to use, and include +code from other sources beyond [crates.io]. + +[Crater]: https://github.com/brson/taskcluster-crater + +**Incremental compilation**. Rust has always had a "crate-wide" +compilation model. This means that the Rust compiler reads in all of +the source files in your crate at once. These are type-checked and +then given to LLVM for optimization. This approach is really great for +doing deep optimization, because it gives LLVM full access to the +entire set of code, allowing for more better inlining, more precise +analysis, and so forth. However, it can mean that turnaround is slow: +even if you only edit one function, we will recompile everything. When +projects get large, this can be a burden. + +The incremental compilation project aims to change this by having the +Rust compiler save intermediate by-products and re-use them. This way, +when you're debugging a problem, or tweaking a code path, you only +have to recompile those things that you have changed, which should +make the "edit-compile-test" cycle much faster. + +Part of this project is restructuring the compiler to introduce a new +intermediate representation, which we call [MIR][mir]. MIR is a kind +of simplified form of Rust code that hides a lot of the details from +full Rust. This is a crucial enabler for language changes like +non-lexical lifetimes (discussing in the next section). [mir]: https://github.com/rust-lang/rfcs/pull/1211 -**IDE integration**. +**IDE integration**. Top-notch IDE support can help to make Rust even +more productive. Up until now, pioneering projects like +[Racer][racer], [Visual Rust][visualrust], and [Rust DT][rustdt] have +been working largely without compiler support. We intend to extend the +compiler to permit deeper integration; the plan is to focus initially +on two IDEs, and then grow from there. + +[syntax highlighting]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md +[racer]: https://github.com/phildawes/racer +[visualrust]: https://github.com/PistonDevelopers/VisualRust +[rustdt]: https://github.com/RustDT/RustDT #### Zeroing in: closing key gaps in our features @@ -117,7 +175,7 @@ match map.find(&key) { Some(...) => { ... } None => { map.insert(key, new_value); - } + } } ~~~~ @@ -143,16 +201,49 @@ macro expansion as well. #### Branching out: taking Rust to new places -**Cross-compilation**. - -**Cargo install**. [RFC][cargoinstall] - -[cargoinstall]: https://github.com/rust-lang/rfcs/pull/1200 - -**Tracing hooks**. One of the most promising way of using Rust is by "embedding" -Rust code into systems written in higher-level languages like [Ruby][skylight] -or Python. This embedding is usually done by giving the Rust code a C API, and -works reasonably well when the target sports a "C friendly" memory management -scheme like reference counting or conservative GC. +**Cross-compilation**. While cross-compiling with Rust is possible +today, it involves a lot of manual configuration. We're shooting to +make it a streamlined, simple process. The idea is that compiling Rust code +for another target should be easy: + +1. Download a precompiled version of `libstd` for the target in question, + if you don't already have it. +2. Execute `cargo build --target=foo`. +3. There is no step 3. + +**Cargo install**. Cargo and [crates.io] is a really great tool for +distributing libaries, but it lacks any means to install executables. +[RFC 1200] describes a simple addition to cargo, the `cargo install` +command. Much like the conventional `make install`, `cargo install` +will place an executable in your path so that you can run it. This can +serve as a simple distribution channel, and is particularly useful for +people writing tools that target Rust developers (who are likely to be +familiar with running cargo). + +[RFC 1200]: https://github.com/rust-lang/rfcs/pull/1200 + +**Tracing hooks**. One of the most promising way of using Rust is by +"embedding" Rust code into systems written in higher-level languages +like [Ruby][skylight] or Python. This embedding is usually done by +giving the Rust code a C API, and works reasonably well when the +target sports a "C friendly" memory management scheme like reference +counting or conservative GC. However, integrating with an environment +that uses a more advanced GC can be quite challenging. Perhaps the +most prominent examples are JavaScript engines like V8 (used by +[node.js]) and SpiderMonkey (used by [Firefox] and +[Servo]). Integrating with those engines requires very careful coding +to ensure that all objects are properly rooted; small mistakes can +easily lead to crashes. These are precisely the kind of memory +management problems that Rust is intended to eliminate. To address +this gap, we plan to extend the compiler with the ability to generate +"trace hooks". These hooks can be used by a GC to sweep the stack and +identify roots, making it possible to write code that integrates with +advanced VMs smoothly and easily. Naturally, the design will respect +Rust's "pay for what you use" policy, so that code which does not +integrate with a GC is unaffected. [skylight]: http://blog.skylight.io/bending-the-curve-writing-safe-fast-native-gems-with-rust/ +[crates.io]: https://crates.io +[nodejs]: https://nodejs.org/ +[Servo]: https://github.com/servo/servo +[Firefox]: http://firefox.com/ From 5009c12e9415e772b9eda0de21df658599995252 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 13 Aug 2015 11:31:16 -0700 Subject: [PATCH 177/386] Refactor the 'next year' post --- _posts/2015-08-13-Next-year.md | 80 +++++++++++++++++++++------------- 1 file changed, 49 insertions(+), 31 deletions(-) diff --git a/_posts/2015-08-13-Next-year.md b/_posts/2015-08-13-Next-year.md index 806e62035..edc9016ad 100644 --- a/_posts/2015-08-13-Next-year.md +++ b/_posts/2015-08-13-Next-year.md @@ -5,46 +5,38 @@ author: Nicholas Matsakis and Aaron Turon description: "Our vision for Rust in 2016." --- -It's now been 12 weeks since the release of Rust 1.0, and we'd like to take this -opportunity to **talk a bit about what 1.0 meant in hindsight, and where Rust is -going in the next year**. +This week marks three months since Rust 1.0 was released. As we're starting to +hit our post-1.0 stride, we'd like to talk about **what 1.0 meant in hindsight, +and where we see Rust going in the next year**. -### The next year of Rust - -> We recently held the first-ever Rust conference, [RustCamp][rustcamp] 2015, -which sold out with 160 attendees. It was amazing to see so much of the Rust -community in person, and to see the vibe of our online spaces translate into a -friendly and approachable meatspace event. The day opened with a keynote from -Nicholas Matsakis and Aaron Turon laying out the core team's view of where we -are and where we're headed. The -[slides are available online](http://rustcamp.com/RustCampKeynote.pdf), but this -post serves as the missing soundtrack. +#### What 1.0 was about -[rustcamp]: http://rustcamp.com/ +Rust 1.0 addressed three key concerns: clarity, stability, and +community. -#### What 1.0 was about +* Stability, we've discussed quite a bit in +[previous posts][deliverable] introducing our release channels and stabilization +process. -In hindsight, Rust 1.0 was about nailing down three key concerns: clarity, -stability, and community. Stability, we've discussed quite a bit in -[previous posts][deliverable]. And, of course, community has always been one of -Rust's greatest strengths. But in the year leading up to 1.0 in particular, we -introduced and refined the [RFC process][rfcs], culminating with -[subteams][subteams] to manage RFCs in each particular area. Community-wide -debate on RFCs was indispensable for delivering a quality 1.0 release. +* Community has always been one of Rust's greatest strengths. But in +the year leading up to 1.0, we introduced and refined the [RFC process][rfcs], +culminating with [subteams][subteams] to manage RFCs in each particular +area. Community-wide debate on RFCs was indispensable for delivering a quality +1.0 release. -All of this refinement prior to 1.0 was in service of clarifying what Rust +* All of this refinement prior to 1.0 was in service of clarifying what Rust represents: -- Memory safety without garbage collection -- [Concurrency without data races][fearless] -- [Abstraction without overhead][traits] -- [Stability without stagnation][deliverable] + - Memory safety without garbage collection + - [Concurrency without data races][fearless] + - [Abstraction without overhead][traits] + - [Stability without stagnation][deliverable] Altogether, **Rust is exciting because it is empowering: you can hack without fear**. And you can do so in contexts you might not have before, dropping down from Ruby or Python, making your first foray into systems programming. -That's Rust 1.0; what's next? +That's Rust 1.0; but what comes next? [deliverable]: http://blog.rust-lang.org/2014/10/30/Stability.html [rfcs]: https://github.com/rust-lang/rfcs#when-you-need-to-follow-this-process @@ -78,7 +70,7 @@ whether any code has stopped compiling recently. We've been using the current version of crater for some time. For example, we regularly compare the nightly release against the latest stable build. We also use crater to check in-progress branches and -estimate the impact of a change. +estimate the impact of a change. Interestingly, we have often found that when code stops compiling, it's not because of a bug in the compiler. Rather, it's because we @@ -104,7 +96,7 @@ doing deep optimization, because it gives LLVM full access to the entire set of code, allowing for more better inlining, more precise analysis, and so forth. However, it can mean that turnaround is slow: even if you only edit one function, we will recompile everything. When -projects get large, this can be a burden. +projects get large, this can be a burden. The incremental compilation project aims to change this by having the Rust compiler save intermediate by-products and re-use them. This way, @@ -175,7 +167,7 @@ match map.find(&key) { Some(...) => { ... } None => { map.insert(key, new_value); - } + } } ~~~~ @@ -247,3 +239,29 @@ integrate with a GC is unaffected. [nodejs]: https://nodejs.org/ [Servo]: https://github.com/servo/servo [Firefox]: http://firefox.com/ + +#### Epilogue: RustCamp 2015, and Rust's community in 2016 + +We recently held the first-ever Rust conference, [RustCamp][rustcamp] 2015, +which sold out with 160 attendees. It was amazing to see so much of the Rust +community in person, and to see the vibe of our online spaces translate into a +friendly and approachable in-person event. The day opened with a keynote from +Nicholas Matsakis and Aaron Turon laying out the core team's view of where we +are and where we're headed. The +[slides are available online](http://rustcamp.com/RustCampKeynote.pdf), and the +above serves as the missing soundtrack. + +There was a definite theme of the day: Rust's greatest potential is to unlock a +new generation of systems programmers. And that's not just because of the +language; it's just as much because of a community culture that says "Don't know +the difference between the stack and the heap? Don't worry, Rust is a great way +to learn about it, and I'd love to show you how." + +The technical work we outlined above is important for our vision in 2016, but so +is the work of those on our moderation and community teams, and all of those who +tirelessly -- enthusiastically -- welcome people coming from all kinds of +backgrounds into the Rust community. So our greatest wish for the next year of +Rust is that, as the community grows, it continues to retain the welcoming +spirit that it has today. + +[rustcamp]: http://rustcamp.com/ From daa0c19f2d866a82e2aa653313590a104373edd8 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 13 Aug 2015 16:23:21 -0700 Subject: [PATCH 178/386] Tweak emphasis in 'next year' post --- _posts/2015-08-13-Next-year.md | 202 ++++++++++++++++----------------- 1 file changed, 99 insertions(+), 103 deletions(-) diff --git a/_posts/2015-08-13-Next-year.md b/_posts/2015-08-13-Next-year.md index edc9016ad..6b51c6917 100644 --- a/_posts/2015-08-13-Next-year.md +++ b/_posts/2015-08-13-Next-year.md @@ -1,8 +1,8 @@ --- layout: post -title: "The next year of Rust" +title: "Rust into 2016" author: Nicholas Matsakis and Aaron Turon -description: "Our vision for Rust in 2016." +description: "Our vision for Rust's next year" --- This week marks three months since Rust 1.0 was released. As we're starting to @@ -11,15 +11,13 @@ and where we see Rust going in the next year**. #### What 1.0 was about -Rust 1.0 addressed three key concerns: clarity, stability, and -community. +Rust 1.0 focused on clarity, stability, and community. -* Stability, we've discussed quite a bit in -[previous posts][deliverable] introducing our release channels and stabilization -process. +* Stability, we've discussed quite a bit in [previous posts][deliverable] +introducing our release channels and stabilization process. -* Community has always been one of Rust's greatest strengths. But in -the year leading up to 1.0, we introduced and refined the [RFC process][rfcs], +* Community has always been one of Rust's greatest strengths. But in the year +leading up to 1.0, we introduced and refined the [RFC process][rfcs], culminating with [subteams][subteams] to manage RFCs in each particular area. Community-wide debate on RFCs was indispensable for delivering a quality 1.0 release. @@ -27,14 +25,15 @@ area. Community-wide debate on RFCs was indispensable for delivering a quality * All of this refinement prior to 1.0 was in service of clarifying what Rust represents: - - Memory safety without garbage collection + - [Memory safety without garbage collection][fearless] - [Concurrency without data races][fearless] - [Abstraction without overhead][traits] - [Stability without stagnation][deliverable] Altogether, **Rust is exciting because it is empowering: you can hack without fear**. And you can do so in contexts you might not have before, dropping down -from Ruby or Python, making your first foray into systems programming. +from languages like Ruby or Python, making your first foray into systems +programming. That's Rust 1.0; but what comes next? @@ -58,66 +57,64 @@ Let's look at some of the biggest plans in each of these categories. #### Doubling down: infrastructure investments -**Crater**. One of our big goals with Rust is that upgrades between -versions should be "hassle-free". An important part of this story is -detecting compiler bugs that cause code to stop working. Naturally, -the compiler has its own large test suite, but that is only a small -fraction of the code that's out there "in the wild". [Crater] is a -tool that aims to close that gap by testing the compiler against all -the packages found in [crates.io], giving us a much better idea -whether any code has stopped compiling recently. - -We've been using the current version of crater for some time. For -example, we regularly compare the nightly release against the latest -stable build. We also use crater to check in-progress branches and -estimate the impact of a change. - -Interestingly, we have often found that when code stops compiling, -it's not because of a bug in the compiler. Rather, it's because we -*fixed* a bug, and that code happened to be relying on the older -behavior. Even in those cases, using crater lets us improve the -experience. For example, for changes that affect a lot of projects, -we've often chosen to phase in the change gradually. In such cases, we -issue one release where users get warnings, and only start issuing -errors on the next release, giving people time to migrate their code. - -Over the next year or so, we plan to improve crater in numerous ways. -For example, we'd like to extend the coverage to other platforms (not -just linux). We'd also like to make it smoother to use, and include -code from other sources beyond [crates.io]. +**Crater**. Our basic [stability promise][deliverable] for Rust is that upgrades +between versions are be "hassle-free". To deliver on this promise, we need to +detect compiler bugs that cause code to stop working. Naturally, the compiler +has its own large test suite, but that is only a small fraction of the code +that's out there "in the wild". **[Crater] is a tool that aims to close that gap +by testing the compiler against all the packages found in [crates.io], giving us +a much better idea whether any code has stopped compiling on the latest nightly.** + +Crater has quickly become an indispensable tool. We regularly compare the +nightly release against the latest stable build, and we use crater to check +in-progress branches and estimate the impact of a change. + +Interestingly, we have often found that when code stops compiling, it's not +because of a bug in the compiler. Rather, it's because we *fixed* a bug, and +that code happened to be relying on the older behavior. Even in those cases, +using crater helps us improve the experience, by suggestion that we should phase +fixes in slowly with warnings. + +Over the next year or so, we plan to improve crater in numerous ways: + +- Extend the coverage to other platforms beyond Linux, and run test suites on + covered libraries as well. +- Make it easier to use: leave an `@crater: test` comment to try out a PR. +- Produce a version of the tool that library authors can use to see effects of + their changes on downstream code. +- Include code from other sources beyond [crates.io]. [Crater]: https://github.com/brson/taskcluster-crater -**Incremental compilation**. Rust has always had a "crate-wide" -compilation model. This means that the Rust compiler reads in all of -the source files in your crate at once. These are type-checked and -then given to LLVM for optimization. This approach is really great for -doing deep optimization, because it gives LLVM full access to the -entire set of code, allowing for more better inlining, more precise -analysis, and so forth. However, it can mean that turnaround is slow: -even if you only edit one function, we will recompile everything. When -projects get large, this can be a burden. - -The incremental compilation project aims to change this by having the -Rust compiler save intermediate by-products and re-use them. This way, -when you're debugging a problem, or tweaking a code path, you only -have to recompile those things that you have changed, which should -make the "edit-compile-test" cycle much faster. +**Incremental compilation**. Rust has always had a "crate-wide" compilation +model. This means that the Rust compiler reads in all of the source files in +your crate at once. These are type-checked and then given to LLVM for +optimization. This approach is great for doing deep optimization, because it +gives LLVM full access to the entire set of code, allowing for more better +inlining, more precise analysis, and so forth. However, it can mean that +turnaround is slow: even if you only edit one function, we will recompile +everything. When projects get large, this can be a burden. + +The incremental compilation project aims to change this by having the Rust +compiler save intermediate by-products and re-use them. This way, when you're +debugging a problem, or tweaking a code path, **you only have to recompile those +things that you have changed, which should make the "edit-compile-test" cycle +much faster**. Part of this project is restructuring the compiler to introduce a new -intermediate representation, which we call [MIR][mir]. MIR is a kind -of simplified form of Rust code that hides a lot of the details from -full Rust. This is a crucial enabler for language changes like -non-lexical lifetimes (discussing in the next section). +intermediate representation, which we call [MIR][mir]. MIR is a simpler, +lower-level form of Rust code that boils down the more complex features, making +the rest of the compiler simpler. This is a crucial enabler for language changes +like non-lexical lifetimes (discussing in the next section). [mir]: https://github.com/rust-lang/rfcs/pull/1211 -**IDE integration**. Top-notch IDE support can help to make Rust even -more productive. Up until now, pioneering projects like -[Racer][racer], [Visual Rust][visualrust], and [Rust DT][rustdt] have -been working largely without compiler support. We intend to extend the -compiler to permit deeper integration; the plan is to focus initially -on two IDEs, and then grow from there. +**IDE integration**. Top-notch IDE support can help to make Rust even more +productive. Up until now, pioneering projects like [Racer][racer], +[Visual Rust][visualrust], and [Rust DT][rustdt] have been working largely +without compiler support. **We plan to extend the compiler to permit deeper +integration with IDEs and other tools**; the plan is to focus initially on two +IDEs, and then grow from there. [syntax highlighting]: https://github.com/rust-lang/rust/blob/master/src/etc/CONFIGS.md [racer]: https://github.com/phildawes/racer @@ -148,11 +145,11 @@ collection can provide only one implementation that works for *all* iterator types, which requires actually calling `.next()` repeatedly. In some cases, you could hand code it better, e.g. by just calling `memcpy`. -To close this gap, we've proposed [specialization][specialization], allowing you -to provide multiple, overlapping trait implementations as long as one is clearly -more specific than the other. Aside from giving Rust a more complete toolkit for -zero-cost abstraction, specialization also improves its story for code -reuse. See [the RFC][specialization] for more details. +To close this gap, we've proposed **[specialization][specialization], allowing +you to provide multiple, overlapping trait implementations as long as one is +clearly more specific than the other**. Aside from giving Rust a more complete +toolkit for zero-cost abstraction, specialization also improves its story for +code reuse. See [the RFC][specialization] for more details. [specialization]: https://github.com/rust-lang/rfcs/pull/1210 @@ -184,54 +181,53 @@ comes with macros that, at compile time, turn regular expressions directly into machine code to match them. Or the [rust-postgres-macros crage][postgres], which checks at compile time for valid SQL syntax. Crates like these and others make use of a highly-unstable compiler plugin system that currently exposes far too -many compiler internals. We plan in the next couple of months to propose a new, -robust design that closes these holes and provides good support for hygienic -macro expansion as well. +many compiler internals. **We plan to propose a new plugin design that is more +robust and provides built-in support for hygienic macro expansion as well**. [regex]: https://github.com/rust-lang/regex [postgres]: https://github.com/sfackler/rust-postgres-macros #### Branching out: taking Rust to new places -**Cross-compilation**. While cross-compiling with Rust is possible -today, it involves a lot of manual configuration. We're shooting to -make it a streamlined, simple process. The idea is that compiling Rust code -for another target should be easy: +**Cross-compilation**. While cross-compiling with Rust is possible today, it +involves a lot of manual configuration. **We're shooting for push-button +cross-compiles**. The idea is that compiling Rust code for another target should +be easy: 1. Download a precompiled version of `libstd` for the target in question, if you don't already have it. 2. Execute `cargo build --target=foo`. 3. There is no step 3. -**Cargo install**. Cargo and [crates.io] is a really great tool for -distributing libaries, but it lacks any means to install executables. -[RFC 1200] describes a simple addition to cargo, the `cargo install` -command. Much like the conventional `make install`, `cargo install` -will place an executable in your path so that you can run it. This can -serve as a simple distribution channel, and is particularly useful for -people writing tools that target Rust developers (who are likely to be -familiar with running cargo). +**Cargo install**. Cargo and [crates.io] is a really great tool for distributing +libaries, but it lacks any means to install executables. [RFC 1200] describes a +simple addition to cargo, the `cargo install` command. Much like the +conventional `make install`, **`cargo install` will place an executable in your +path so that you can run it**. This can serve as a simple distribution channel, +and is particularly useful for people writing tools that target Rust developers +(who are likely to be familiar with running cargo). [RFC 1200]: https://github.com/rust-lang/rfcs/pull/1200 -**Tracing hooks**. One of the most promising way of using Rust is by -"embedding" Rust code into systems written in higher-level languages -like [Ruby][skylight] or Python. This embedding is usually done by -giving the Rust code a C API, and works reasonably well when the -target sports a "C friendly" memory management scheme like reference -counting or conservative GC. However, integrating with an environment -that uses a more advanced GC can be quite challenging. Perhaps the -most prominent examples are JavaScript engines like V8 (used by -[node.js]) and SpiderMonkey (used by [Firefox] and -[Servo]). Integrating with those engines requires very careful coding -to ensure that all objects are properly rooted; small mistakes can -easily lead to crashes. These are precisely the kind of memory -management problems that Rust is intended to eliminate. To address -this gap, we plan to extend the compiler with the ability to generate -"trace hooks". These hooks can be used by a GC to sweep the stack and -identify roots, making it possible to write code that integrates with -advanced VMs smoothly and easily. Naturally, the design will respect -Rust's "pay for what you use" policy, so that code which does not +**Tracing hooks**. One of the most promising ways of using Rust is by "embedding" +Rust code into systems written in higher-level languages like [Ruby][skylight] +or Python. This embedding is usually done by giving the Rust code a C API, and +works reasonably well when the target sports a "C friendly" memory management +scheme like reference counting or conservative GC. + +Integrating with an environment that uses a more advanced GC can be +quite challenging. Perhaps the most prominent examples are JavaScript engines +like V8 (used by [node.js]) and SpiderMonkey (used by [Firefox] and +[Servo]). Integrating with those engines requires very careful coding to ensure +that all objects are properly rooted; small mistakes can easily lead to +crashes. These are precisely the kind of memory management problems that Rust is +intended to eliminate. + +**To bring Rust to environments with advanced GCs, we plan to extend the +compiler with the ability to generate "trace hooks"**. These hooks can be used +by a GC to sweep the stack and identify roots, making it possible to write code +that integrates with advanced VMs smoothly and easily. Naturally, the design +will respect Rust's "pay for what you use" policy, so that code which does not integrate with a GC is unaffected. [skylight]: http://blog.skylight.io/bending-the-curve-writing-safe-fast-native-gems-with-rust/ @@ -248,8 +244,8 @@ community in person, and to see the vibe of our online spaces translate into a friendly and approachable in-person event. The day opened with a keynote from Nicholas Matsakis and Aaron Turon laying out the core team's view of where we are and where we're headed. The -[slides are available online](http://rustcamp.com/RustCampKeynote.pdf), and the -above serves as the missing soundtrack. +[slides are available online](http://rustcamp.com/schedule.html) (along with +several other talks), and the above serves as the missing soundtrack. There was a definite theme of the day: Rust's greatest potential is to unlock a new generation of systems programmers. And that's not just because of the From 8c986afae34390e47f3583a7378d664f741cb86d Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:09:55 -0700 Subject: [PATCH 179/386] Adjust date for 'next year' post --- _posts/{2015-08-13-Next-year.md => 2015-08-14-Next-year.md} | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) rename _posts/{2015-08-13-Next-year.md => 2015-08-14-Next-year.md} (98%) diff --git a/_posts/2015-08-13-Next-year.md b/_posts/2015-08-14-Next-year.md similarity index 98% rename from _posts/2015-08-13-Next-year.md rename to _posts/2015-08-14-Next-year.md index 6b51c6917..242b67dea 100644 --- a/_posts/2015-08-13-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -45,9 +45,9 @@ That's Rust 1.0; but what comes next? #### Where we go from here -After much discussion within the core team and with the broader community, we've -identified a number of improvements we'd like to make over the course of the -next or so, falling into three broad categories: +After much discussion within the core team, early production users, and the +broader community, we've identified a number of improvements we'd like to make +over the course of the next or so, falling into three categories: - Doubling down on infrastructure; - Zeroing in on gaps in key features; From 9379b23655d7f6b0d1f9d0c3f4b27e4fd87a2d34 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:15:44 -0700 Subject: [PATCH 180/386] Minor tweaks to 'next year' --- _posts/2015-08-14-Next-year.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 242b67dea..889d2d0b6 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -1,6 +1,6 @@ --- layout: post -title: "Rust into 2016" +title: "Rust in 2016" author: Nicholas Matsakis and Aaron Turon description: "Our vision for Rust's next year" --- @@ -121,7 +121,7 @@ IDEs, and then grow from there. [visualrust]: https://github.com/PistonDevelopers/VisualRust [rustdt]: https://github.com/RustDT/RustDT -#### Zeroing in: closing key gaps in our features +#### Zeroing in: closing gaps in our key features **Specialization**. The idea of zero-cost abstractions breaks down into two separate goals, as identified by Stroustrup: @@ -257,7 +257,7 @@ The technical work we outlined above is important for our vision in 2016, but so is the work of those on our moderation and community teams, and all of those who tirelessly -- enthusiastically -- welcome people coming from all kinds of backgrounds into the Rust community. So our greatest wish for the next year of -Rust is that, as the community grows, it continues to retain the welcoming +Rust is that, as its community grows, it continues to retain the welcoming spirit that it has today. [rustcamp]: http://rustcamp.com/ From b4b6ab52f214e94e31cc60cc994e8fe4595e7eb5 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:18:56 -0700 Subject: [PATCH 181/386] More emph --- _posts/2015-08-14-Next-year.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 889d2d0b6..6e003042c 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -13,17 +13,17 @@ and where we see Rust going in the next year**. Rust 1.0 focused on clarity, stability, and community. -* Stability, we've discussed quite a bit in [previous posts][deliverable] +* **Stability**, we've discussed quite a bit in [previous posts][deliverable] introducing our release channels and stabilization process. -* Community has always been one of Rust's greatest strengths. But in the year +* **Community** has always been one of Rust's greatest strengths. But in the year leading up to 1.0, we introduced and refined the [RFC process][rfcs], culminating with [subteams][subteams] to manage RFCs in each particular area. Community-wide debate on RFCs was indispensable for delivering a quality 1.0 release. -* All of this refinement prior to 1.0 was in service of clarifying what Rust -represents: +* All of this refinement prior to 1.0 was in service of reaching **clarity* on +what Rust represents: - [Memory safety without garbage collection][fearless] - [Concurrency without data races][fearless] From db77039fe91d88e39f7f61ac7382bd9e0dc01033 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:19:30 -0700 Subject: [PATCH 182/386] Typo fix --- _posts/2015-08-14-Next-year.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 6e003042c..9f97b43ed 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -22,7 +22,7 @@ culminating with [subteams][subteams] to manage RFCs in each particular area. Community-wide debate on RFCs was indispensable for delivering a quality 1.0 release. -* All of this refinement prior to 1.0 was in service of reaching **clarity* on +* All of this refinement prior to 1.0 was in service of reaching **clarity** on what Rust represents: - [Memory safety without garbage collection][fearless] From 7af6f6e5cd346cb1ab90418431619521c277f4ec Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:24:15 -0700 Subject: [PATCH 183/386] Format changes --- _posts/2015-08-14-Next-year.md | 70 +++++++++++++++++++++------------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 9f97b43ed..069e9457a 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -9,7 +9,7 @@ This week marks three months since Rust 1.0 was released. As we're starting to hit our post-1.0 stride, we'd like to talk about **what 1.0 meant in hindsight, and where we see Rust going in the next year**. -#### What 1.0 was about +### What 1.0 was about Rust 1.0 focused on clarity, stability, and community. @@ -43,7 +43,7 @@ That's Rust 1.0; but what comes next? [fearless]: http://blog.rust-lang.org/2015/04/10/Fearless-Concurrency.html [traits]: http://blog.rust-lang.org/2015/05/11/traits.html -#### Where we go from here +### Where we go from here After much discussion within the core team, early production users, and the broader community, we've identified a number of improvements we'd like to make @@ -55,9 +55,11 @@ over the course of the next or so, falling into three categories: Let's look at some of the biggest plans in each of these categories. -#### Doubling down: infrastructure investments +### Doubling down: infrastructure investments -**Crater**. Our basic [stability promise][deliverable] for Rust is that upgrades +#### Crater + +Our basic [stability promise][deliverable] for Rust is that upgrades between versions are be "hassle-free". To deliver on this promise, we need to detect compiler bugs that cause code to stop working. Naturally, the compiler has its own large test suite, but that is only a small fraction of the code @@ -86,7 +88,9 @@ Over the next year or so, we plan to improve crater in numerous ways: [Crater]: https://github.com/brson/taskcluster-crater -**Incremental compilation**. Rust has always had a "crate-wide" compilation +#### Incremental compilation + +Rust has always had a "crate-wide" compilation model. This means that the Rust compiler reads in all of the source files in your crate at once. These are type-checked and then given to LLVM for optimization. This approach is great for doing deep optimization, because it @@ -105,11 +109,13 @@ Part of this project is restructuring the compiler to introduce a new intermediate representation, which we call [MIR][mir]. MIR is a simpler, lower-level form of Rust code that boils down the more complex features, making the rest of the compiler simpler. This is a crucial enabler for language changes -like non-lexical lifetimes (discussing in the next section). +like non-lexical lifetimes (discussed in the next section). [mir]: https://github.com/rust-lang/rfcs/pull/1211 -**IDE integration**. Top-notch IDE support can help to make Rust even more +#### IDE integration + +Top-notch IDE support can help to make Rust even more productive. Up until now, pioneering projects like [Racer][racer], [Visual Rust][visualrust], and [Rust DT][rustdt] have been working largely without compiler support. **We plan to extend the compiler to permit deeper @@ -121,9 +127,11 @@ IDEs, and then grow from there. [visualrust]: https://github.com/PistonDevelopers/VisualRust [rustdt]: https://github.com/RustDT/RustDT -#### Zeroing in: closing gaps in our key features +### Zeroing in: closing gaps in our key features -**Specialization**. The idea of zero-cost abstractions breaks down into two +#### Specialization + +The idea of zero-cost abstractions breaks down into two separate goals, as identified by Stroustrup: - What you don't use, you don't pay for. @@ -153,11 +161,12 @@ code reuse. See [the RFC][specialization] for more details. [specialization]: https://github.com/rust-lang/rfcs/pull/1210 -**Borrow checker improvements**. The borrow checker is, in a way, the beating -heart of Rust; it's the part of the compiler that lets us achieve memory safety -without garbage collection, by catching use-after-free bugs and the like. But -occasionally, the borrower checker also "catches" non-bugs, like the following -pattern: +#### Borrow checker improvements + +The borrow checker is, in a way, the beating heart of Rust; it's the part of the +compiler that lets us achieve memory safety without garbage collection, by +catching use-after-free bugs and the like. But occasionally, the borrower +checker also "catches" non-bugs, like the following pattern: ~~~~rust match map.find(&key) { @@ -175,7 +184,9 @@ shortcoming soon by refactoring the borrow checker to view code in terms of finer-grained ("non-lexical") regions -- a step made possible by the move to the MIR mentioned above. -**Plugins**. There are some really neat things you can do in Rust today -- if +#### Plugins + +There are some really neat things you can do in Rust today -- if you're willing to use the Nightly channel. For example, the [regex crate][regex] comes with macros that, at compile time, turn regular expressions directly into machine code to match them. Or the [rust-postgres-macros crage][postgres], which @@ -187,19 +198,22 @@ robust and provides built-in support for hygienic macro expansion as well**. [regex]: https://github.com/rust-lang/regex [postgres]: https://github.com/sfackler/rust-postgres-macros -#### Branching out: taking Rust to new places +### Branching out: taking Rust to new places + +#### Cross-compilation -**Cross-compilation**. While cross-compiling with Rust is possible today, it -involves a lot of manual configuration. **We're shooting for push-button -cross-compiles**. The idea is that compiling Rust code for another target should -be easy: +While cross-compiling with Rust is possible today, it involves a lot of manual +configuration. **We're shooting for push-button cross-compiles**. The idea is +that compiling Rust code for another target should be easy: 1. Download a precompiled version of `libstd` for the target in question, if you don't already have it. 2. Execute `cargo build --target=foo`. 3. There is no step 3. -**Cargo install**. Cargo and [crates.io] is a really great tool for distributing +#### Cargo install + +Cargo and [crates.io] is a really great tool for distributing libaries, but it lacks any means to install executables. [RFC 1200] describes a simple addition to cargo, the `cargo install` command. Much like the conventional `make install`, **`cargo install` will place an executable in your @@ -209,11 +223,13 @@ and is particularly useful for people writing tools that target Rust developers [RFC 1200]: https://github.com/rust-lang/rfcs/pull/1200 -**Tracing hooks**. One of the most promising ways of using Rust is by "embedding" -Rust code into systems written in higher-level languages like [Ruby][skylight] -or Python. This embedding is usually done by giving the Rust code a C API, and -works reasonably well when the target sports a "C friendly" memory management -scheme like reference counting or conservative GC. +#### Tracing hooks + +One of the most promising ways of using Rust is by "embedding" Rust code into +systems written in higher-level languages like [Ruby][skylight] or Python. This +embedding is usually done by giving the Rust code a C API, and works reasonably +well when the target sports a "C friendly" memory management scheme like +reference counting or conservative GC. Integrating with an environment that uses a more advanced GC can be quite challenging. Perhaps the most prominent examples are JavaScript engines @@ -236,7 +252,7 @@ integrate with a GC is unaffected. [Servo]: https://github.com/servo/servo [Firefox]: http://firefox.com/ -#### Epilogue: RustCamp 2015, and Rust's community in 2016 +### Epilogue: RustCamp 2015, and Rust's community in 2016 We recently held the first-ever Rust conference, [RustCamp][rustcamp] 2015, which sold out with 160 attendees. It was amazing to see so much of the Rust From b012c75a65272a4362cac31b6ae218e1b5193d40 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:27:56 -0700 Subject: [PATCH 184/386] Typo --- _posts/2015-08-14-Next-year.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 069e9457a..03a364067 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -60,7 +60,7 @@ Let's look at some of the biggest plans in each of these categories. #### Crater Our basic [stability promise][deliverable] for Rust is that upgrades -between versions are be "hassle-free". To deliver on this promise, we need to +between versions are "hassle-free". To deliver on this promise, we need to detect compiler bugs that cause code to stop working. Naturally, the compiler has its own large test suite, but that is only a small fraction of the code that's out there "in the wild". **[Crater] is a tool that aims to close that gap From 63a753c4c720829f0a9d3bae732ee005bc8f8450 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:36:14 -0700 Subject: [PATCH 185/386] More typos --- _posts/2015-08-14-Next-year.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 03a364067..2c94a0a19 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -186,11 +186,11 @@ MIR mentioned above. #### Plugins -There are some really neat things you can do in Rust today -- if -you're willing to use the Nightly channel. For example, the [regex crate][regex] -comes with macros that, at compile time, turn regular expressions directly into -machine code to match them. Or the [rust-postgres-macros crage][postgres], which -checks at compile time for valid SQL syntax. Crates like these and others make +There are some really neat things you can do in Rust today -- if you're willing +to use the Nightly channel. For example, the [regex crate][regex] comes with +macros that, at compile time, turn regular expressions directly into machine +code to match them. Or take the [rust-postgres-macros crate][postgres], which +checks strings for SQL syntax validity at compile time. Crates like these make use of a highly-unstable compiler plugin system that currently exposes far too many compiler internals. **We plan to propose a new plugin design that is more robust and provides built-in support for hygienic macro expansion as well**. From b2de9b3a04a9acbbf4ffd6e356db9460c36c4d5c Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 08:47:47 -0700 Subject: [PATCH 186/386] Match sentence and bullet order --- _posts/2015-08-14-Next-year.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 2c94a0a19..0436448b4 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -11,7 +11,7 @@ and where we see Rust going in the next year**. ### What 1.0 was about -Rust 1.0 focused on clarity, stability, and community. +Rust 1.0 focused on stability, community, and clarity. * **Stability**, we've discussed quite a bit in [previous posts][deliverable] introducing our release channels and stabilization process. From 0ddd16bcb239103c89478f57a1ef048b6f5b2494 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 10:32:27 -0700 Subject: [PATCH 187/386] Talks link --- _posts/2015-08-14-Next-year.md | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 0436448b4..732670e29 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -254,14 +254,17 @@ integrate with a GC is unaffected. ### Epilogue: RustCamp 2015, and Rust's community in 2016 -We recently held the first-ever Rust conference, [RustCamp][rustcamp] 2015, -which sold out with 160 attendees. It was amazing to see so much of the Rust -community in person, and to see the vibe of our online spaces translate into a -friendly and approachable in-person event. The day opened with a keynote from -Nicholas Matsakis and Aaron Turon laying out the core team's view of where we -are and where we're headed. The -[slides are available online](http://rustcamp.com/schedule.html) (along with -several other talks), and the above serves as the missing soundtrack. +We recently held the first-ever Rust conference, [RustCamp][rustcamp] +2015, which sold out with 160 attendees. It was amazing to see so much +of the Rust community in person, and to see the vibe of our online +spaces translate into a friendly and approachable in-person event. The +day opened with a keynote from Nicholas Matsakis and Aaron Turon +laying out the core team's view of where we are and where we're +headed. The +[slides are available online](http://rustcamp.com/schedule.html) +(along with several other talks), and the above serves as the missing +soundtrack. **Update**: now you can see +[the talks](http://confreaks.tv/events/rustcamp2015) as well! There was a definite theme of the day: Rust's greatest potential is to unlock a new generation of systems programmers. And that's not just because of the From 716010fec6400f275f2ce21a27672a94c2ca82d0 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Fri, 14 Aug 2015 11:29:31 -0700 Subject: [PATCH 188/386] fix node.js link --- _posts/2015-08-14-Next-year.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 732670e29..669164bde 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -248,7 +248,7 @@ integrate with a GC is unaffected. [skylight]: http://blog.skylight.io/bending-the-curve-writing-safe-fast-native-gems-with-rust/ [crates.io]: https://crates.io -[nodejs]: https://nodejs.org/ +[node.js]: https://nodejs.org/ [Servo]: https://github.com/servo/servo [Firefox]: http://firefox.com/ From 42deb3b1d3115870a6501a7d39559924344493e7 Mon Sep 17 00:00:00 2001 From: Anders Pitman Date: Sat, 15 Aug 2015 10:38:02 -0700 Subject: [PATCH 189/386] Fix a couple small typos --- _posts/2015-08-14-Next-year.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2015-08-14-Next-year.md b/_posts/2015-08-14-Next-year.md index 669164bde..f2638d5f9 100644 --- a/_posts/2015-08-14-Next-year.md +++ b/_posts/2015-08-14-Next-year.md @@ -47,7 +47,7 @@ That's Rust 1.0; but what comes next? After much discussion within the core team, early production users, and the broader community, we've identified a number of improvements we'd like to make -over the course of the next or so, falling into three categories: +over the course of the next year or so, falling into three categories: - Doubling down on infrastructure; - Zeroing in on gaps in key features; @@ -147,7 +147,7 @@ pub trait Extend { } ~~~~ -The `Extend` trait provides a nice abstraction for insert data from any kind of +The `Extend` trait provides a nice abstraction for inserting data from any kind of iterator into a collection. But with traits today, that also means that each collection can provide only one implementation that works for *all* iterator types, which requires actually calling `.next()` repeatedly. In some cases, you From 926b12840083ff846c93855080a0a1003c1e2cbf Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 17 Sep 2015 08:55:03 -0700 Subject: [PATCH 190/386] Rust 1.3 announcement --- _posts/2015-09-17-Rust-1.3.md | 188 ++++++++++++++++++++++++++++++++++ 1 file changed, 188 insertions(+) create mode 100644 _posts/2015-09-17-Rust-1.3.md diff --git a/_posts/2015-09-17-Rust-1.3.md b/_posts/2015-09-17-Rust-1.3.md new file mode 100644 index 000000000..43208fd05 --- /dev/null +++ b/_posts/2015-09-17-Rust-1.3.md @@ -0,0 +1,188 @@ +--- +layout: post +title: "Announcing Rust 1.3" +author: The Rust Core Team +--- + +The gear keeps turning: we're releasing Rust 1.3 stable today! As always, read +on for the highlights and check the [release notes][notes] for more detail. + +[install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-130-september-2015 + +### What's in 1.3 stable + +This is our first release shipping with the +[Rustonomicon](https://doc.rust-lang.org/nightly/nomicon/), a new book covering +"The Dark Arts of Advanced and Unsafe Rust Programming". While it's still in +draft form, this book already provides deep coverage of some of Rust's darker +corners. + +On the library front, we saw a fair amount of API stabilization, including the +new `Duration` API and enhancements to `Error` and `Hash`/`Hasher`. We expect to +see further growth of the `std::time` module in the 1.5 timeframe. + +The 1.3 cycle also saw continuing focus on performance. Most wins here are +within the standard library: + +- The substring matcher now uses a + [more efficient algorithm](https://github.com/rust-lang/rust/pull/26327). +- There were + [improvements to zero filling](https://github.com/rust-lang/rust/pull/26849) + that speed up `Vec::resize` and `Read::read_to_end`. +- The implementation of `Read::read_to_end` has been + [specialized for `stdin` and `File`](https://github.com/rust-lang/rust/pull/26950), + resulting in additional speedups. +- The `PartialEq` implementation on slices is now + [much faster](https://github.com/rust-lang/rust/pull/26884). + +We're continuing to invest in Windows, with +[preliminary support for targeting Windows XP](https://github.com/rust-lang/rust/pull/26601). While +we do not intend to treat Windows XP as a "first tier" platform, it is now +feasible to build Rust code for XP as long as you avoid certain parts of the +standard library. Work on MSVC toolchain integration is ongoing, with full +support (on 64-bit) shipping in the 1.4 beta today. + +On the Cargo front, we have landed support for +[lint capping](https://github.com/rust-lang/rust/pull/27260) as specified by an +[earlier RFC](https://github.com/rust-lang/rfcs/pull/1193). The idea is that +lints in your dependencies should not affect your ability to compile cleanly, +which in turn makes it easier to tweak the way lints work without undue hassle +in the ecosystem. + +### Contributors to 1.3 + +Rust is a community-driven language, and we're delighted to thank the 131 +contributors to this release: + +- Aaron Turon +- Adam Heins +- Agoston Szepessy +- Aidan Hobson Sayers +- Akos Kiss +- Alex Crichton +- Alex Newman +- Alexis Beingessner +- Alisdair Owens +- Andreas Tolfsen +- Andrew Kuchev +- Andrew Paseltiner +- Andy Caldwell +- Andy Grover +- Antti Keränen +- Ariel Ben-Yehuda +- Barosl Lee +- Benjamin Herr +- Björn Steinbrink +- Blake Loring +- Brian Anderson +- Brody Holden +- Chris Morgan +- Christian Persson +- Christian Weinz +- Cole Reynolds +- Corey Farwell +- Corey Richardson +- Cristian Kubis +- Cruz Julian Bishop +- Daniel Albert +- Dave Huseby +- Dirkjan Ochtman +- Eduard Burtescu +- Eli Friedman +- Eljay +- Esption +- Felix S. Klock II +- Florian Hartwig +- Frank McSherry +- FuGangqiang +- Geoffrey Thomas +- Georg Brandl +- Guillaume Gomez +- Huon Wilson +- Ivan Ukhov +- Jan Likar +- Jared Roesch +- Jashank Jeremy +- Jason Schein +- Jeehoon Kang +- Jesús Espino +- Johannes Oertel +- John Hodge +- Jonathan Hansford +- Jonathan Reem +- Jose Narvaez +- Josh Triplett +- Joshua Landau +- Kagami Sascha Rosylight +- Kelvin Ly +- Ken Tossell +- Kevin Ballard +- Kevin Butler +- Kieran Hunt +- Kornel Lesiński +- Kristof Söderström +- Lee Jeffery +- Leif Arne Storset +- Liigo Zhuang +- Makoto Kato +- Manish Goregaokar +- Marcus Klaas +- Mark Buer +- Mathieu David +- Mathijs van de Nes +- Matt Friedman +- Michael Sproul +- Michael Woerister +- Ms2ger +- Nick Cameron +- Nick Hamann +- Nick Howell +- Nicolette Verlinden +- Niko Matsakis +- OGINO Masanori +- Oliver Schneider +- P1start +- Paolo Falabella +- Pascal Hertleif +- Patrick Walton +- Pavel Pravosud +- Peter Atashian +- Peter Elmers +- Ralf Jung +- Remi Rampin +- Richo Healey +- Ryan Pendleton +- Scott Olson +- Sean Patrick Santos +- Seo Sanghyeon +- Simon Sapin +- Simonas Kazlauskas +- Steve Klabnik +- Steven Allen +- Steven Fackler +- Steven Stewart-Gallus +- Sébastien Marie +- Taliesin Beynon +- Tamir Duberstein +- Theo Belaire +- Ticki +- Tobias Bucher +- Tshepang Lekhonkhobe +- Ulrik Sverdrup +- Vadim Chugunov +- Vadim Petrochenkov +- Vincent Bernat +- Vladimir Rutsky +- Wei-Ming Yang +- Wesley Wiser +- William Throwe +- arthurprs +- bors +- diaphore +- eternaleye +- jethrogb +- krumelmonster +- mdinger +- midinastasurazz +- mitaa From 9fef34b72598e5a77a450edc77a3065f101c0a18 Mon Sep 17 00:00:00 2001 From: Caspar Krieger Date: Thu, 22 Oct 2015 21:17:46 +1100 Subject: [PATCH 191/386] Remove Caspar's email address --- _posts/2015-04-03-Rust-1.0-beta.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-04-03-Rust-1.0-beta.md b/_posts/2015-04-03-Rust-1.0-beta.md index 867681c87..0f5633069 100644 --- a/_posts/2015-04-03-Rust-1.0-beta.md +++ b/_posts/2015-04-03-Rust-1.0-beta.md @@ -102,7 +102,7 @@ release: - `Camille Roussel ` - `Camille TJHOA ` - `Carol Nichols ` -- `Caspar Krieger ` +- `Caspar Krieger` - `Ches Martin ` - `Chloe <5paceToast@users.noreply.github.com>` - `Chris Wong ` From 78f4213c4e649b71e61363c106ec3713c1fea061 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 28 Oct 2015 16:52:01 -0400 Subject: [PATCH 192/386] Rust 1.4 release announcement --- _posts/2015-10-29-Rust-1.4.md | 224 ++++++++++++++++++++++++++++++++++ 1 file changed, 224 insertions(+) create mode 100644 _posts/2015-10-29-Rust-1.4.md diff --git a/_posts/2015-10-29-Rust-1.4.md b/_posts/2015-10-29-Rust-1.4.md new file mode 100644 index 000000000..485f866f6 --- /dev/null +++ b/_posts/2015-10-29-Rust-1.4.md @@ -0,0 +1,224 @@ +--- +layout: post +title: "Announcing Rust 1.4" +author: The Rust Core Team +--- + +Choo choo! The trains have kept rolling, and today, we’re happy to announce the +release of Rust 1.4, the newest stable release. Rust is a systems programming +language focused on safety, speed, and concurrency. + +As always, you can [install Rust 1.4][install] from the appropriate page on our +website, and check out the [detailed release notes for 1.4][notes] on GitHub as +well. About 1200 patches were landed in this release. + +[install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-140-october-2015 + +### What's in 1.4 stable + +The story of 1.4 is mostly one of improvements and stabilizations, rather than +new features. + +However, there is one particular change which is a language fix that enables a +new feature: [RFC 1214, “Clarify (and improve) rules for projections and +well-formedness”](https://github.com/rust-lang/rfcs/pull/1214). While that’s +a deeply technical title, the TL;DR is that we found some weaknesses in the +definition and implementation of a few aspects of the type system. This RFC +fixes these problems. Given that changes to the type system like this can cause +regressions, but fixes like this are important for soundness, Rust 1.4 will +warn on any code that violates the new rules, but still compile. These warnings +will turn into errors in Rust 1.5. However, given the train model, the +community has had time to deal with these changes while 1.4 was in beta, and +the small number of crates we were aware of have already been fixed. + +These soundness fixes enable the return of the ‘scoped threads’ feature, in +which you can create threads that reference data stored on the stack in a +safe manner. A few crates have implemented this feature, most notably +[crossbeam] and [scoped_threadpool]. See their documentation for more +information. + +[crossbeam]: https://crates.io/crates/crossbeam +[scoped_threadpool]: https://crates.io/crates/scoped_threadpool + +[RFC 1212](https://github.com/rust-lang/rfcs/blob/master/text/1212-line-endings.md) +is also in this release, which changes all functions dealing with reading +‘lines’ to treat both `\n` and `\r\n` as a valid line-ending. This was +determined during the RFC process to be a bugfix, but we’re mentioning it +here to raise awareness. The older behavior of only dealing with `\n` made +for surprising behavior, where your crate would work well on Linux and Mac OS +X, but fail on Windows. This fix brings these functions more in-line (😉) +with expectations. + +Rust 1.4 marks an upgrade in our Windows support: Windows builds targeting the +64-bit MSVC ABI and linker (instead of GNU) are now supported and recommended +for general use, and will appear on the downloads page for the first time. +Thank you to all who have helped us work out the kinks since support initially +landed in Rust 1.2. + +Here’s a summary of library changes: + +* 48 APIs were stabilized. +* Eight APIs were deprecated. +* Two were made faster. +* Over ten various types implement new traits. + +See the [release notes][libnotes] for exact details. + +[libnotes]: https://github.com/brson/rust/blob/relnotes/RELEASES.md#libraries + +The compiler [no longer uses +`morestack`](https://github.com/rust-lang/rust/pull/27338), which was a +holdover implementation detail from long, long ago. We now use guard pages +and stack probes instead, though stack probes are only implemented on Windows +so far. + +Finally, one major Cargo improvement: [`cargo update` will now print extra +information about what it is +changing.](https://github.com/rust-lang/cargo/pull/1931) For example: + +```text +$ cargo update + Updating registry `https://github.com/rust-lang/crates.io-index` + Updating libc v0.1.8 -> v0.1.10 + Updating memchr v0.1.3 -> v0.1.5 + Updating num v0.1.26 -> v0.1.27 + Updating rand v0.3.9 -> v0.3.10 + Updating rustc-serialize v0.3.15 -> v0.3.16 +``` + +Before, it would do this job silently. + +### Contributors to 1.4 + +Rust is a community-driven project, and we're very appreciative of the work of +the 127 contributors who made 1.4 happen. Thank you! + +- Adam Crume +- Aidan Hobson Sayers +- Aleksey Kladov +- Alex Burka +- Alex Crichton +- Alex Ozdemir +- AlexDenisov +- Alexis Beingessner +- Alisdair Owens +- Andre Bogus +- Andrea Canciani +- Andrew Paseltiner +- Ariel Ben-Yehuda +- Artem Shitov +- Barosl Lee +- benshu +- Björn Steinbrink +- bors +- Brian Anderson +- Cesar Eduardo Barros +- Chris Krycho +- Chris Morgan +- Chris Nixon +- Chris Wong +- christopherdumas +- Cody P Schafer +- Corey Farwell +- Daan Rijks +- Dave Huseby +- diaphore +- Diggory Blake +- Dong Zhou +- Dylan McKay +- Elaine "See More" Nemo +- Eli Friedman +- Eljay +- Erick Tryzelaar +- Felix S. Klock II +- Garming Sam +- Georg Brandl +- Gleb Kozyrev +- Guillaume Gomez +- Hunan Rostomyan +- Huon Wilson +- Ivan Jager +- Jack Wilson +- Jake Goulding +- Jake Kerr +- Jake Shadle +- James Miller +- Jan Likar +- Jared Roesch +- Jeehoon Kang +- John Thomas +- Jonas Schievink +- Jørn Lode +- Jose Narvaez +- jotomicron +- Kang Seonghoon +- Kornel Lesiński +- Lee Jeffery +- Leif Arne Storset +- Lennart Kudling +- llogiq +- Manish Goregaokar +- Marc-Antoine Perennou +- Marcus Klaas +- Marko Lalic +- Martin Wernstål +- Matěj Grabovský +- Matej Lach +- Matt Brubeck +- Matt Friedman +- Michael Choate +- Michael Layzell +- Michael Macias +- Michael McConville +- Michael Neumann +- Mickaël Salaün +- midinastasurazz +- Mike Marcacci +- mitaa +- Ms2ger +- Murarth +- Nathan Kleyn +- Nicholas Seckar +- Nick Cameron +- Nick Howell +- Niko Matsakis +- Nikolay Kondratyev +- Niranjan Padmanabhan +- Overmind JIANG +- Pascal Hertleif +- Peter Reid +- Remi Rampin +- Richard Diamond +- Robin Kruppe +- Ruby +- Ryo Munakata +- Scott Olson +- Sean Bowe +- Sean McArthur +- Sébastien Marie +- Simon Mazur +- Simon Sapin +- Simonas Kazlauskas +- Stepan Koltsov +- Steve Klabnik +- Steven Fackler +- Sylvestre Ledru +- Taliesin Beynon +- Tamir Duberstein +- Tim Cuthbertson +- Tim JIANG +- Tim Neumann +- Tobias Bucher +- Tshepang Lekhonkhobe +- Ulrik Sverdrup +- Vadim Chugunov +- Vadim Petrochenkov +- Viacheslav Chimishuk +- Victor Berger +- Vincent Bernat +- Vladimir Rutsky +- w00ns +- William Throwe +- Without Boats +- Xiao Chuan Yu From 4f7b0c030407c37b9860c74825ff3f11af1c3ecb Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 29 Oct 2015 14:13:41 -0400 Subject: [PATCH 193/386] Link to actual 1.4 release notes rather than master --- _posts/2015-10-29-Rust-1.4.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2015-10-29-Rust-1.4.md b/_posts/2015-10-29-Rust-1.4.md index 485f866f6..c695ec266 100644 --- a/_posts/2015-10-29-Rust-1.4.md +++ b/_posts/2015-10-29-Rust-1.4.md @@ -13,7 +13,7 @@ website, and check out the [detailed release notes for 1.4][notes] on GitHub as well. About 1200 patches were landed in this release. [install]: http://www.rust-lang.org/install.html -[notes]: https://github.com/rust-lang/rust/blob/master/RELEASES.md#version-140-october-2015 +[notes]: https://github.com/rust-lang/rust/blob/8ab8581f6921bc7a8e3fa4defffd2814372dcb15/RELEASES.md#version-140-october-2015 ### What's in 1.4 stable From bce3fa308427b3f9e9ff3083720fb9e1c15d8674 Mon Sep 17 00:00:00 2001 From: Manish Goregaokar Date: Sat, 31 Oct 2015 06:00:54 +0530 Subject: [PATCH 194/386] Update concurrency post to mention current state of scoped threads --- _posts/2015-04-10-Fearless-Concurrency.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/_posts/2015-04-10-Fearless-Concurrency.md b/_posts/2015-04-10-Fearless-Concurrency.md index 29f10090a..d6db9733d 100644 --- a/_posts/2015-04-10-Fearless-Concurrency.md +++ b/_posts/2015-04-10-Fearless-Concurrency.md @@ -475,6 +475,12 @@ Disaster averted. ### Sharing the stack: "scoped" +_Note: The API mentioned here is an old one which has been moved out of +the standard library. You can find equivalent functionality in +[`crossbeam`][crossbeam-crate] ([documentation for `scope()`][crossbeam-doc]) +and [`scoped_threadpool`][scoped-threadpool-crate] +([documentation for `scoped()`][scoped-threadpool-doc])_ + So far, all the patterns we've seen involve creating data structures on the heap that get shared between threads. But what if we wanted to start some threads that make use of data living in our stack frame? @@ -611,3 +617,7 @@ months. Stay tuned! [scoped]: http://static.rust-lang.org/doc/master/std/thread/fn.scoped.html [syncbox]: https://github.com/carllerche/syncbox [simple_parallel]: https://github.com/huonw/simple_parallel +[crossbeam-crate]: https://crates.io/crates/crossbeam +[crossbeam-doc]: http://aturon.github.io/crossbeam-doc/crossbeam/fn.scope.html +[scoped-threadpool-crate]: https://crates.io/crates/scoped_threadpool +[scoped-threadpool-doc]: http://kimundi.github.io/scoped-threadpool-rs/scoped_threadpool/index.html#examples: From 774d5134cff0cc28ecc8963bab008a1d15800872 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 10 Dec 2015 09:36:05 -0500 Subject: [PATCH 195/386] Rust 1.5 announcement --- _posts/2015-12-10-Rust-1.5.md | 197 ++++++++++++++++++++++++++++++++++ 1 file changed, 197 insertions(+) create mode 100644 _posts/2015-12-10-Rust-1.5.md diff --git a/_posts/2015-12-10-Rust-1.5.md b/_posts/2015-12-10-Rust-1.5.md new file mode 100644 index 000000000..d8065f2e4 --- /dev/null +++ b/_posts/2015-12-10-Rust-1.5.md @@ -0,0 +1,197 @@ +--- +layout: post +title: "Announcing Rust 1.5" +author: The Rust Core Team +--- + +Today we're releasing [Rust 1.5 stable][install]. This post gives the +highlights, and you can find the full details in the +[release notes][notes]. + +[install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-150-2015-12-10 + +### What's in 1.5 stable + +The biggest news with Rust 1.5 is the introduction of `cargo install`, +a new subcommand that installs Cargo application packages on the local +system. This tool offers a painless way to distribute Rust applications. + +The community is already taking advantage of `cargo install` to +install applications like +[rustfmt](https://github.com/rust-lang-nursery/rustfmt), the +work-in-progress code formatting tool for Rust. Moreover, `cargo install` +can also be used to install new subcommands for Cargo itself. Many of +these are collected in the +[Cargo extras](https://github.com/kbknapp/cargo-extras) package: + +* `cargo check`: statically check a project, but don't build a binary. +* `cargo edit`: add or remove dependencies for a project through the command line. +* `cargo graph`: build dependency graphs for a project using GraphViz. +* `cargo watch`: automatically re-run a Cargo command when the project changes. + +In addition to these tooling changes, Rust 1.5 sees a large number of +library API stabilizations, especially around the interaction of paths +and the file system. + +Finally, there were a few improvements to compile times, and crate +metadata shrunk +[by about 20%](https://github.com/rust-lang/rust/pull/28521). + +### Contributors to 1.5 + +The Rust community continues to do incredible work, and we'd like to +thank the 152 contributors to this release: + +- Aaron Turon +- Adolfo Ochagavía +- Ahmed Charles +- Aidan Hobson Sayers +- Aleksey Kladov +- Alex Burka +- Alex Crichton +- Alex Gaynor +- Alexis Beingessner +- Alfie John +- Amit Aryeh Levy +- Andre Bogus +- Andrea Canciani +- Andreas Sommer +- Andrew Chin +- Andrew Paseltiner +- Ariel Ben-Yehuda +- Barosl Lee +- Bastien Dejean +- Ben S +- Ben Sago +- Björn Steinbrink +- Boris Egorov +- Brian Anderson +- Bryce Van Dyk +- Carlos Liam +- Carol (Nichols || Goulding) +- Charlotte Spencer +- Chris C Cerami +- Chris Drake +- Chris Wong +- Colin Wallace +- Corentin Henry +- Corey Farwell +- Craig Hills +- Cristi Cobzarenco +- Cristian Kubis +- Dan W. +- Daniel Carral +- Daniel Keep +- Dato Simó +- David Elliott +- David Ripton +- David Szotten +- DenisKolodin +- Dominik Inführ +- Dongie Agnir +- Eduard Burtescu +- Eli Friedman +- Eljay +- Emanuel Czirai +- Fabiano Beselga +- Felix S. Klock II +- Florian Hahn +- Florian Hartwig +- Garming Sam +- Gavin Baker +- Gleb Kozyrev +- Guillaume Gomez +- Huon Wilson +- Irving A.J. Rivas Z. +- J. Ryan Stinnett +- Jack Wilson +- James Bell +- James McGlashan +- Jan Likar +- Jan-Erik Rediger +- Jed Davis +- Jethro Beekman +- John Hodge +- Jonas Schievink +- Jonathan Hansford +- Jorge Aparicio +- Jose Narvaez +- Joseph Caudle +- Keshav Kini +- Kevin Butler +- Kevin Yap +- Kyle Robinson Young +- Lee Jeffery +- Lee Jenkins +- Lennart Kudling +- Liigo Zhuang +- Luqman Aden +- Manish Goregaokar +- Marcello Seri +- Marcus Klaas +- Martin Pool +- Matt Brubeck +- Michael Howell +- Michael Layzell +- Michael Pankov +- Ms2ger +- Nick Cameron +- Nick Hamann +- Nick Howell +- Niko Matsakis +- Oliver Schneider +- Peter Atashian +- Peter Marheine +- Philipp Oppermann +- Remi Rampin +- Reza Akhavan +- Ricardo Signes +- Richard Diamond +- Robert Gardner +- Robin Kruppe +- Ruud van Asseldonk +- Ryan Scheel +- Scott Olson +- Sean Bowe +- Sebastian Wicki +- Seeker14491 +- Seo Sanghyeon +- Simon Mazur +- Simon Sapin +- Simonas Kazlauskas +- Stefan O'Rear +- Steve Klabnik +- Steven Allen +- Steven Fackler +- Sébastien Marie +- Ted Mielczarek +- Tobias Bucher +- Tshepang Lekhonkhobe +- Ulrik Sverdrup +- Utkarsh Kukreti +- Vadim Chugunov +- Vadim Petrochenkov +- Vitali Haravy +- Vladimir Rutsky +- Wesley Wiser +- Will Speak +- William Throwe +- Willy Aguirre +- Xavier Shay +- Yoshito Komatsu +- arcnmx +- arthurprs +- billpmurphy +- bors +- christopherdumas +- critiqjo +- glendc +- kickinbahk +- llogiq +- mdinger +- nwin +- nxnfufunezn +- panicbit +- skeleten +- whitequark From 48badc3b0bd75c7fa94fe9a8688fa8049c3f3697 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 10 Dec 2015 16:20:35 -0500 Subject: [PATCH 196/386] Stop mentioning cargo-extras, which doesn't build on stable --- _posts/2015-12-10-Rust-1.5.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/_posts/2015-12-10-Rust-1.5.md b/_posts/2015-12-10-Rust-1.5.md index d8065f2e4..ab05ce2e7 100644 --- a/_posts/2015-12-10-Rust-1.5.md +++ b/_posts/2015-12-10-Rust-1.5.md @@ -21,14 +21,14 @@ The community is already taking advantage of `cargo install` to install applications like [rustfmt](https://github.com/rust-lang-nursery/rustfmt), the work-in-progress code formatting tool for Rust. Moreover, `cargo install` -can also be used to install new subcommands for Cargo itself. Many of -these are collected in the -[Cargo extras](https://github.com/kbknapp/cargo-extras) package: +can also be used to install new subcommands for Cargo itself: -* `cargo check`: statically check a project, but don't build a binary. -* `cargo edit`: add or remove dependencies for a project through the command line. -* `cargo graph`: build dependency graphs for a project using GraphViz. -* `cargo watch`: automatically re-run a Cargo command when the project changes. +* `cargo-check`: statically check a project, but don't build a binary. +* `cargo-edit`: add or remove dependencies for a project through the command line. +* `cargo-graph`: build dependency graphs for a project using GraphViz. +* `cargo-watch`: automatically re-run a Cargo command when the project changes. + +(You can find more with a [crates.io search](https://crates.io/search?q=subcommand).) In addition to these tooling changes, Rust 1.5 sees a large number of library API stabilizations, especially around the interaction of paths From 8387cbaf4b42cf3a96163958c51cb8091377d261 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Tue, 19 Jan 2016 16:54:10 -0500 Subject: [PATCH 197/386] 1.6 release announcement --- _posts/2016-01-21-Rust-1.6.md | 78 +++++++++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) create mode 100644 _posts/2016-01-21-Rust-1.6.md diff --git a/_posts/2016-01-21-Rust-1.6.md b/_posts/2016-01-21-Rust-1.6.md new file mode 100644 index 000000000..37c1e02f7 --- /dev/null +++ b/_posts/2016-01-21-Rust-1.6.md @@ -0,0 +1,78 @@ +--- +layout: post +title: "Announcing Rust 1.6" +author: The Rust Core Team +--- + +Hello 2016! We’re happy to announce the first Rust release of the year, 1.6. +Rust is a systems programming language focused on safety, speed, and +concurrency. + +As always, you can [install Rust 1.6][install] from the appropriate page on our +website, and check out the [detailed release notes for 1.6][notes] on GitHub. +About 1100 patches were landed in this release. + +[install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-160-2016-01-21 + +### What's in 1.6 stable + +This release contains a number of small refinements, one major feature, and +a change to [Crates.io](https://crates.io). + +#### libcore stabilization + +The largest new feature in 1.6 is that [`libcore`] is now stable! Rust’s standard +library is two-tiered: `libcore` contains a lot of functionality, but more important +is what it does _not_ contain: significant dependencies. `libcore` is completely +platform agnostic, and requires only a handful of external symbols to be defined. +Rust’s `libstd` builds on top of `libcore`, adding support for memory allocation, +I/O, and concurrency. Applications using Rust in the embedded space, as well as +those writing operating systems, often eschew `libstd`, using only `libcore`. + +[`libcore`]: http://doc.rust-lang.org/nightly/core/ + +`libcore` being stabilized is a major step towards being able to write the lowest +levels of software using stable Rust. There’s still future work to be done, however, +so expect to hear more about this in future release notes. + +#### Library stabilizations + +About 30 library functions and methods are now stable in 1.6. Notable +improvements include: + +The `drain()` family of functions on collections. These methods let you move +elements out of a collection while allowing them to retain their backing +memory, reducing allocation in certain situations. + +A number of implementations of `From` for converting between standard library +types, mainly between various integral and floating-point types. + +Finally, `Vec::extend_from_slice()`, which was previously known as +`push_all()`. This method has a significantly faster implementation than the +more general `extend()`. + +See the detailed release notes linked above for more. + +#### Crates.io disallows wildcards + +If you maintain a crate on [Crates.io](https://crates.io), you might have seen +a warning: newly uploaded crates are no longer allowed to use a wildcard when +describing their dependencies. In other words, this is not allowed: + +```toml +[dependencies] +regex = "*" +``` + +Instead, you must actually specify a specific version or range of versions, +using one of the `semver` crate’s various options: `^`, `~`, or `=`. + +A wildcard dependency means that you work with any possible version of your +dependency. This is highly unlikely to be true, and causes unnecessary breakage +in the ecosystem. We’ve been advertising this change as a warning for some time; +now it’s time to turn it into an error. + +### Contributors to 1.6 + +TODO From 01cfb6ec9f1a3f6d399023352a919fb6c65a7628 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 20 Jan 2016 13:43:01 -0500 Subject: [PATCH 198/386] tweaks as per @aturon's feedback --- _posts/2016-01-21-Rust-1.6.md | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/_posts/2016-01-21-Rust-1.6.md b/_posts/2016-01-21-Rust-1.6.md index 37c1e02f7..cb60b0a92 100644 --- a/_posts/2016-01-21-Rust-1.6.md +++ b/_posts/2016-01-21-Rust-1.6.md @@ -22,19 +22,22 @@ a change to [Crates.io](https://crates.io). #### libcore stabilization -The largest new feature in 1.6 is that [`libcore`] is now stable! Rust’s standard -library is two-tiered: `libcore` contains a lot of functionality, but more important -is what it does _not_ contain: significant dependencies. `libcore` is completely -platform agnostic, and requires only a handful of external symbols to be defined. -Rust’s `libstd` builds on top of `libcore`, adding support for memory allocation, -I/O, and concurrency. Applications using Rust in the embedded space, as well as -those writing operating systems, often eschew `libstd`, using only `libcore`. +The largest new feature in 1.6 is that [`libcore`] is now stable! Rust’s +standard library is two-tiered: there’s a small core library, `libcore`, and +the full standard library, `libstd`, that builds on top of it. `libcore` is +completely platform agnostic, and requires only a handful of external symbols +to be defined. Rust’s `libstd` builds on top of `libcore`, adding support for +memory allocation, I/O, and concurrency. Applications using Rust in the +embedded space, as well as those writing operating systems, often eschew +`libstd`, using only `libcore`. [`libcore`]: http://doc.rust-lang.org/nightly/core/ -`libcore` being stabilized is a major step towards being able to write the lowest -levels of software using stable Rust. There’s still future work to be done, however, -so expect to hear more about this in future release notes. +`libcore` being stabilized is a major step towards being able to write the +lowest levels of software using stable Rust. There’s still future work to be +done, however. This will allow for a library ecosystem to develop around +`libcore`, but _applications_ are not fully supported yet. Expect to hear more +about this in future release notes. #### Library stabilizations @@ -52,7 +55,7 @@ Finally, `Vec::extend_from_slice()`, which was previously known as `push_all()`. This method has a significantly faster implementation than the more general `extend()`. -See the detailed release notes linked above for more. +See the [detailed release notes][notes] for more. #### Crates.io disallows wildcards @@ -65,8 +68,11 @@ describing their dependencies. In other words, this is not allowed: regex = "*" ``` -Instead, you must actually specify a specific version or range of versions, -using one of the `semver` crate’s various options: `^`, `~`, or `=`. +Instead, you must actually specify [a specific version or range of +versions][versions], using one of the `semver` crate’s various options: `^`, +`~`, or `=`. + +[versions]: http://doc.crates.io/crates-io.html#using-cratesio-based-crates A wildcard dependency means that you work with any possible version of your dependency. This is highly unlikely to be true, and causes unnecessary breakage From 38388888a1649b7a4ec733d352c4a6cef8a42f24 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 21 Jan 2016 14:02:11 -0500 Subject: [PATCH 199/386] add contributors --- _posts/2016-01-21-Rust-1.6.md | 135 +++++++++++++++++++++++++++++++++- 1 file changed, 134 insertions(+), 1 deletion(-) diff --git a/_posts/2016-01-21-Rust-1.6.md b/_posts/2016-01-21-Rust-1.6.md index cb60b0a92..4e117bd4b 100644 --- a/_posts/2016-01-21-Rust-1.6.md +++ b/_posts/2016-01-21-Rust-1.6.md @@ -81,4 +81,137 @@ now it’s time to turn it into an error. ### Contributors to 1.6 -TODO +We had 132 individuals contribute to 1.6. Thank you so much! + +* Aaron Turon +* Adam Badawy +* Aleksey Kladov +* Alexander Bulaev +* Alex Burka +* Alex Crichton +* Alex Gaynor +* Alexis Beingessner +* Amanieu d'Antras +* Amit Saha +* Andrea Canciani +* Andrew Paseltiner +* androm3da +* angelsl +* Angus Lees +* Antti Keränen +* arcnmx +* Ariel Ben-Yehuda +* Ashkan Kiani +* Barosl Lee +* Benjamin Herr +* Ben Striegel +* Bhargav Patel +* Björn Steinbrink +* Boris Egorov +* bors +* Brian Anderson +* Bruno Tavares +* Bryce Van Dyk +* Cameron Sun +* Christopher Sumnicht +* Cole Reynolds +* corentih +* Daniel Campbell +* Daniel Keep +* Daniel Rollins +* Daniel Trebbien +* Danilo Bargen +* Devon Hollowood +* Doug Goldstein +* Dylan McKay +* ebadf +* Eli Friedman +* Eric Findlay +* Erik Davidson +* Felix S. Klock II +* Florian Hahn +* Florian Hartwig +* Gleb Kozyrev +* Guillaume Gomez +* Huon Wilson +* Igor Shuvalov +* Ivan Ivaschenko +* Ivan Kozik +* Ivan Stankovic +* Jack Fransham +* Jake Goulding +* Jake Worth +* James Miller +* Jan Likar +* Jean Maillard +* Jeffrey Seyfried +* Jethro Beekman +* John Kåre Alsaker +* John Talling +* Jonas Schievink +* Jonathan S +* Jose Narvaez +* Josh Austin +* Josh Stone +* Joshua Holmer +* JP Sugarbroad +* jrburke +* Kevin Butler +* Kevin Yeh +* Kohei Hasegawa +* Kyle Mayes +* Lee Jeffery +* Manish Goregaokar +* Marcell Pardavi +* Markus Unterwaditzer +* Martin Pool +* Marvin Löbel +* Matt Brubeck +* Matthias Bussonnier +* Matthias Kauer +* mdinger +* Michael Layzell +* Michael Neumann +* Michael Sproul +* Michael Woerister +* Mihaly Barasz +* Mika Attila +* mitaa +* Ms2ger +* Nicholas Mazzuca +* Nick Cameron +* Niko Matsakis +* Ole Krüger +* Oliver Middleton +* Oliver Schneider +* Ori Avtalion +* Paul A. Jungwirth +* Peter Atashian +* Philipp Matthias Schäfer +* pierzchalski +* Ravi Shankar +* Ricardo Martins +* Ricardo Signes +* Richard Diamond +* Rizky Luthfianto +* Ryan Scheel +* Scott Olson +* Sean Griffin +* Sebastian Hahn +* Sébastien Marie +* Seo Sanghyeon +* Simonas Kazlauskas +* Simon Sapin +* Stepan Koltsov +* Steve Klabnik +* Steven Fackler +* Tamir Duberstein +* Tobias Bucher +* Toby Scrace +* Tshepang Lekhonkhobe +* Ulrik Sverdrup +* Vadim Chugunov +* Vadim Petrochenkov +* William Throwe +* xd1le +* Xmasreturns From 18d6d2065f04223de6d3b901da9ea28f45b73eac Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 2 Mar 2016 18:54:47 -0500 Subject: [PATCH 200/386] 1.7 release announcement --- _posts/2016-03-02-Rust-1.7.md | 194 ++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100644 _posts/2016-03-02-Rust-1.7.md diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md new file mode 100644 index 000000000..ce24a1ff5 --- /dev/null +++ b/_posts/2016-03-02-Rust-1.7.md @@ -0,0 +1,194 @@ +--- +layout: post +title: "Announcing Rust 1.7" +author: The Rust Core Team +--- + +The Rust team is happy to announce the latest version of Rust, 1.7. Rust is a +systems programming language focused on safety, speed, and concurrency. + +As always, you can [install Rust 1.7][install] from the appropriate page on our +website, and check out the [detailed release notes for 1.7][notes] on GitHub. +About 1300 patches were landed in this release. + +[install]: http://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-170-2016-03-03 + +### What's in 1.7 stable + +This release contains a number of small refinements, one major feature, and +a change to [Crates.io](https://crates.io). + +#### New Language features + +... there were none! While we have several things cooking for future releases, +the timeframe in which 1.7 included the holidays, which means less time for +commenting on GitHub and more time for spending with loved ones. + +#### Library stabilizations + +About 40 library functions and methods are now stable in 1.7. Notable +improvements include: + +* The ability to customize `HashMap`s and similar data structures with + a custom hashing function. +* `<[T]>::clone_from_slice()`, an efficient way to copy the data from one slice + and put it into another slice. +* Various convenience methods on `Ipv4Addr` and `Ipv6Addr`, such as `is_loopback()`, + which returns `true` or `false` if the address is a loopback address according to + RFC 6890. +* Various improvements to `CString`, used for FFI. +* checked, saturated, and overflowing operations for various numeric types. + These aren’t counted in that ‘40’ number above, because there are a _lot_ of + them, but they all do the same thing. + +See the [detailed release notes][notes] for more. + +### Contributors to 1.7 + +We had 144 individuals contribute to 1.7. Thank you so much! + +* Aaron Turon +* Adam Perry +* Adrian Heine +* Aidan Hobson Sayers +* Aleksey Kladov +* Alexander Lopatin +* Alex Burka +* Alex Crichton +* Ali Clark +* Amanieu d’Antras +* Andrea Bedini +* Andrea Canciani +* Andre Bogus +* Andrew Barchuk +* Andrew Paseltiner +* angelsl +* Anton Blanchard +* arcnmx +* Ariel Ben-Yehuda +* arthurprs +* ashleysommer +* Barosl Lee +* Benjamin Herr +* Björn Steinbrink +* bors +* Brandon W Maister +* Brian Anderson +* Brian Campbell +* Carlos E. Garcia +* Chad Shaffer +* Corey Farwell +* Daan Sprenkels +* Daniel Campbell +* Daniel Robertson +* Dave Hodder +* Dave Huseby +* dileepb +* Dirk Gadsden +* Eduard Burtescu +* Erick Tryzelaar +* est31 +* Evan +* Fabrice Desré +* fbergr +* Felix Gruber +* Felix S. Klock II +* Florian Hahn +* Geoff Catlin +* Geoffrey Thomas +* Georg Brandl +* ggomez +* Gleb Kozyrev +* Gökhan Karabulut +* Greg Chapple +* Guillaume Bonnet +* Guillaume Gomez +* Ivan Kozik +* Jack O’Connor +* Jeffrey Seyfried +* Johan Lorenzo +* Johannes Oertel +* John Hodge +* John Kåre Alsaker +* Jonas Schievink +* Jonathan Reem +* Jonathan S +* Jorge Aparicio +* Josh Stone +* Kamal Marhubi +* Katze +* Keith Yeung +* Kenneth Koski +* Kevin Stock +* Luke Jones +* Manish Goregaokar +* Marc Bowes +* Marvin Löbel +* Masood Malekghassemi +* Matt Brubeck +* Mátyás Mustoha +* Michael Huynh +* Michael Neumann +* Michael Woerister +* mitaa +* mopp +* Nathan Kleyn +* Nicholas Mazzuca +* Nick Cameron +* Nikita Baksalyar +* Niko Matsakis +* NODA, Kai +* nxnfufunezn +* Olaf Buddenhagen +* Oliver ‘ker’ Schneider +* Oliver Middleton +* Oliver Schneider +* Pascal Hertleif +* Paul Dicker +* Paul Smith +* Peter Atashian +* Peter Kolloch +* petevine +* Pierre Krieger +* Piotr Czarnecki +* Prayag Verma +* qpid +* Ravi Shankar +* Reeze Xia +* Richard Bradfield +* Robin Kruppe +* rphmeier +* Ruud van Asseldonk +* Ryan Thomas +* Sandeep Datta +* Scott Olson +* Scott Whittaker +* Sean Leffler +* Sean McArthur +* Sebastian Hahn +* Sebastian Wicki +* Sébastien Marie +* Seo Sanghyeon +* Sergey Veselkov +* Simonas Kazlauskas +* Simon Sapin +* Stepan Koltsov +* Stephan Hügel +* Steve Klabnik +* Steven Allen +* Steven Fackler +* Tamir Duberstein +* tgor +* Thomas Wickham +* Thomas Winwood +* Tobias Bucher +* Tomasz Miąsko +* tormol +* Tshepang Lekhonkhobe +* Ulrik Sverdrup +* Vadim Petrochenkov +* Vincent Esche +* Vlad Ureche +* Wangshan Lu +* Wesley Wiser From 306369b72bb9db916b007afbb98357e3635acc9c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 2 Mar 2016 19:00:56 -0500 Subject: [PATCH 201/386] tweaks --- _posts/2016-03-02-Rust-1.7.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index ce24a1ff5..549e94dba 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -16,14 +16,14 @@ About 1300 patches were landed in this release. ### What's in 1.7 stable -This release contains a number of small refinements, one major feature, and -a change to [Crates.io](https://crates.io). +This release is primarily about library features. While we have several +language features cooking for future releases, the timeframe in which 1.7 +included the holidays, which means less time for commenting on GitHub and more +time for spending with loved ones. #### New Language features -... there were none! While we have several things cooking for future releases, -the timeframe in which 1.7 included the holidays, which means less time for -commenting on GitHub and more time for spending with loved ones. +`None` #### Library stabilizations From 59863d9f46d5dce970b6ff2f0edff887c7e02c0c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 3 Mar 2016 10:16:06 -0500 Subject: [PATCH 202/386] more tweaks, thanks @aturon @alexcrichton --- _posts/2016-03-02-Rust-1.7.md | 67 +++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 7 deletions(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index 549e94dba..a1af0c5df 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -21,17 +21,56 @@ language features cooking for future releases, the timeframe in which 1.7 included the holidays, which means less time for commenting on GitHub and more time for spending with loved ones. -#### New Language features +#### Library stabilizations -`None` +About 40 library functions and methods are now stable in 1.7. One of the +largest APIs stabilized was support for custom hash algorithms in the standard +library’s `HashMap` type. Previously all hash maps would use [SipHash] as +the hashing algorithm, which provides protection against DOS attacks by +default. SipHash, however, is [not very fast] at hashing small keys. As shown, +however, the [FNV hash algorithm] is much faster for these size of inputs. This +means that by switching hash algorithms for types like `HashMap` +there can be a significant speedup so long as the loss of DOS protection is +acceptable. + +[Siphash]: https://en.wikipedia.org/wiki/SipHash +[not very fast]: http://cglab.ca/~abeinges/blah/hash-rs/ +[FNV hash algorithm]: https://en.wikipedia.org/wiki/Fowler%E2%80%93Noll%E2%80%93Vo_hash_function + +To see this in action, you can check out the [fnv crate] on [crates.io] and +create a `HashMap` via: + +```rust +extern crate fnv; + +use std::collections::HashMap; +use std::hash::BuildHasherDefault; +use fnv::FnvHasher; + +type MyHasher = BuildHasherDefault; + +fn main() { + let mut map: HashMap<_, _, MyHasher> = HashMap::default(); + map.insert(1, "Hello"); + map.insert(2, ", world!"); + println!("{:?}", map); +} +``` + +[fnv crate]: https://crates.io/crates/fnv +[crates.io]: https://crates.io -#### Library stabilizations -About 40 library functions and methods are now stable in 1.7. Notable -improvements include: +Note that most of the time you don’t even need to specify the hasher as type +inference will take care of it, so `HashMap::default()` should be all you need +to get up to 2x faster hashes. It’s also worth pointing out that [`Hash`] trait +is agnostic to the hashing algorithm used, so no changes are needed to the +types being inserted into hash maps to reap the benefits! + +[`Hash`]: http://doc.rust-lang.org/std/hash/trait.Hash.html + +Other notable improvements include: -* The ability to customize `HashMap`s and similar data structures with - a custom hashing function. * `<[T]>::clone_from_slice()`, an efficient way to copy the data from one slice and put it into another slice. * Various convenience methods on `Ipv4Addr` and `Ipv6Addr`, such as `is_loopback()`, @@ -44,6 +83,20 @@ improvements include: See the [detailed release notes][notes] for more. +#### Cargo features + +There were a few small updates to Cargo: + +* An [improvement to build scripts] that allows them to precisely inform Cargo + about dependences to ensure that they’re only rerun when those files change. + This should help development quite a bit in repositories with build scripts. +* A [modification to the `cargo rustc` subcommand], which allows specifying + profiles to pull in dev-dependencies during testing and such. + + +[improvment to build scripts]: https://github.com/rust-lang/cargo/pull/2279 +[modification to the `cargo rustc` subcommand]: https://github.com/rust-lang/cargo/pull/2224 + ### Contributors to 1.7 We had 144 individuals contribute to 1.7. Thank you so much! From 9dab7fe1d4d26929de73a77c1891c61e1ebf2de5 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 3 Mar 2016 11:06:49 -0500 Subject: [PATCH 203/386] https --- _posts/2016-03-02-Rust-1.7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index a1af0c5df..181c781ac 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -11,7 +11,7 @@ As always, you can [install Rust 1.7][install] from the appropriate page on our website, and check out the [detailed release notes for 1.7][notes] on GitHub. About 1300 patches were landed in this release. -[install]: http://www.rust-lang.org/install.html +[install]: https://www.rust-lang.org/install.html [notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-170-2016-03-03 ### What's in 1.7 stable From 529cf423d5579aa4d4982c8f0975465b0d5b4afc Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 3 Mar 2016 13:16:15 -0500 Subject: [PATCH 204/386] Thanks @alexcrichton --- _posts/2016-03-02-Rust-1.7.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index 181c781ac..2bb9674b4 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -17,9 +17,9 @@ About 1300 patches were landed in this release. ### What's in 1.7 stable This release is primarily about library features. While we have several -language features cooking for future releases, the timeframe in which 1.7 -included the holidays, which means less time for commenting on GitHub and more -time for spending with loved ones. +language features cooking for future releases, the timeframe in which 1.7 was +developed included the holidays, which means less time for commenting on GitHub +and more time for spending with loved ones. #### Library stabilizations From 5252eb7f3b1066dfa4411d74ee2f75b02b89422f Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Mar 2016 11:14:38 -0800 Subject: [PATCH 205/386] Fix a typo to fix a link. --- _posts/2016-03-02-Rust-1.7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index 2bb9674b4..ab93553bd 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -94,7 +94,7 @@ There were a few small updates to Cargo: profiles to pull in dev-dependencies during testing and such. -[improvment to build scripts]: https://github.com/rust-lang/cargo/pull/2279 +[improvement to build scripts]: https://github.com/rust-lang/cargo/pull/2279 [modification to the `cargo rustc` subcommand]: https://github.com/rust-lang/cargo/pull/2224 ### Contributors to 1.7 From 27dfaeb239ea77a10db5eb17d43a094b5434d79a Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 3 Mar 2016 14:14:50 -0500 Subject: [PATCH 206/386] fix error in link --- _posts/2016-03-02-Rust-1.7.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index 2bb9674b4..ab93553bd 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -94,7 +94,7 @@ There were a few small updates to Cargo: profiles to pull in dev-dependencies during testing and such. -[improvment to build scripts]: https://github.com/rust-lang/cargo/pull/2279 +[improvement to build scripts]: https://github.com/rust-lang/cargo/pull/2279 [modification to the `cargo rustc` subcommand]: https://github.com/rust-lang/cargo/pull/2224 ### Contributors to 1.7 From c2bc67b14b9f26584ee8f2b828bfaba7d61ef614 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 3 Mar 2016 11:20:58 -0800 Subject: [PATCH 207/386] Trim trailing whitespace --- _posts/2016-03-02-Rust-1.7.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index ab93553bd..39cb16f23 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -31,7 +31,7 @@ default. SipHash, however, is [not very fast] at hashing small keys. As shown, however, the [FNV hash algorithm] is much faster for these size of inputs. This means that by switching hash algorithms for types like `HashMap` there can be a significant speedup so long as the loss of DOS protection is -acceptable. +acceptable. [Siphash]: https://en.wikipedia.org/wiki/SipHash [not very fast]: http://cglab.ca/~abeinges/blah/hash-rs/ @@ -43,16 +43,16 @@ create a `HashMap` via: ```rust extern crate fnv; -use std::collections::HashMap; -use std::hash::BuildHasherDefault; -use fnv::FnvHasher; - -type MyHasher = BuildHasherDefault; - +use std::collections::HashMap; +use std::hash::BuildHasherDefault; +use fnv::FnvHasher; + +type MyHasher = BuildHasherDefault; + fn main() { let mut map: HashMap<_, _, MyHasher> = HashMap::default(); - map.insert(1, "Hello"); - map.insert(2, ", world!"); + map.insert(1, "Hello"); + map.insert(2, ", world!"); println!("{:?}", map); } ``` @@ -94,8 +94,8 @@ There were a few small updates to Cargo: profiles to pull in dev-dependencies during testing and such. -[improvement to build scripts]: https://github.com/rust-lang/cargo/pull/2279 -[modification to the `cargo rustc` subcommand]: https://github.com/rust-lang/cargo/pull/2224 +[improvement to build scripts]: https://github.com/rust-lang/cargo/pull/2279 +[modification to the `cargo rustc` subcommand]: https://github.com/rust-lang/cargo/pull/2224 ### Contributors to 1.7 From 8bb33511ac1bad8cf20766b6671f7dd6bf8b057c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 3 Mar 2016 14:24:57 -0500 Subject: [PATCH 208/386] add toby_s https://github.com/rust-lang/rust/commit/33f3c52d32e6f91494bc305fd25f9d5ae5a11702 was in 1.7, but somehow he was not on the list --- _posts/2016-03-02-Rust-1.7.md | 1 + 1 file changed, 1 insertion(+) diff --git a/_posts/2016-03-02-Rust-1.7.md b/_posts/2016-03-02-Rust-1.7.md index ab93553bd..1d615a682 100644 --- a/_posts/2016-03-02-Rust-1.7.md +++ b/_posts/2016-03-02-Rust-1.7.md @@ -236,6 +236,7 @@ We had 144 individuals contribute to 1.7. Thank you so much! * Thomas Wickham * Thomas Winwood * Tobias Bucher +* Toby Scrace * Tomasz Miąsko * tormol * Tshepang Lekhonkhobe From a46cc2ccdb80a1d7bdf3c9191519d188ae75c1d5 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Wed, 13 Apr 2016 12:32:49 -0400 Subject: [PATCH 209/386] 1.8 release announcement --- _posts/2016-04-14-Rust-1.8.md | 251 ++++++++++++++++++++++++++++++++++ 1 file changed, 251 insertions(+) create mode 100644 _posts/2016-04-14-Rust-1.8.md diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md new file mode 100644 index 000000000..ed584e3fe --- /dev/null +++ b/_posts/2016-04-14-Rust-1.8.md @@ -0,0 +1,251 @@ +--- +layout: post +title: "Announcing Rust 1.8" +author: The Rust Core Team +--- + +The Rust team is happy to announce the latest version of Rust, 1.8. Rust is a +systems programming language focused on safety, speed, and concurrency. + +As always, you can [install Rust 1.8][install] from the appropriate page on our +website, and check out the [detailed release notes for 1.8][notes] on GitHub. +About 1400 patches were landed in this release. + +[install]: https://www.rust-lang.org/install.html +[notes]: https://github.com/rust-lang/rust/blob/stable/RELEASES.md#version-180-2016-04-14 + +### What's in 1.8 stable + +There are two new features in Rust 1.8, as well as good news for Windows users! +Additionally, work is underway to replace our `make`-based build system with +one based on Cargo. + +The first feature is that the various “operator equals” operators, such as `+=` +and `-=`, are now overloadable via various traits. This change was accepted in +[RFC 953], and looks like this: + +```rust +use std::ops:: AddAssign; + +#[derive(Debug)] +struct Count { + value: i32, +} + +impl AddAssign for Count { + fn add_assign(&mut self, other: Count) { + self.value += other.value; + } +} + +fn main() { + let mut c1 = Count { value: 1 }; + let c2 = Count { value: 5 }; + + c1 += c2; + + println!("{:?}", c1); +} +``` + +[RFC 953]: https://github.com/rust-lang/rfcs/blob/master/text/0953-op-assign.md + +This will print out `Count { value: 6 }`. Like the other operator traits, an +associated type allows you to use different types on each side of the operator, +as well. See the RFC for more details. + +The second feature is very small, and comes from [RFC 218]. Before Rust 1.8, a +`struct` with no fields did not have curly braces: + +```rust +struct Foo; // works +struct Bar { }; // error +``` + +[RFC 218]: https://github.com/rust-lang/rfcs/blob/master/text/0218-empty-struct-with-braces.md + +The second form is no longer an error, and is equivalent to the first. This was +originally disallowed for consistency with other empty declarations, as well as +a parsing ambiguity. However, that ambiguity is non-existent in post-1.0 Rust, +and macro authors saw additional complexity due to needing a special-case. Also, +users who do active development would sometimes switch between empty and +non-empty versions of a struct, and the extra work and diffs involved was less +than ideal. Allowing both forms is slightly less consistent, but the ergonomics +of these two cases was deemed worth it. + +On the Windows front, 32-bit MSVC builds [now implement unwinding]. This moves +`i686-pc-windows-msvc` to a Tier 1 platform. + +[now implement unwinding]: https://github.com/rust-lang/rust/pull/30448 + +Finally, we have used `make` to build Rust for a very long time. However, +we already have a wonderful tool for building Rust programs: Cargo. In Rust +1.8, [initial support landed] for a new build system that’s written in Rust, +and based on Cargo. It is not yet the default, and there is much more work to +do. We will talk about this in release notes more once it’s completely done, +for now, please read the GitHub issue for more details. + +[initial support landed]: https://github.com/rust-lang/rust/pull/30448 + +#### Library stabilizations + +About 20 library functions and methods are now stable in 1.8. There are three +major groups of changes: UTF-16 related string methods, various APIs related to +time, and the various traits needed for operator overloading mentioned in the +language section. + +Other notable improvements include: + +* `<[T]>::clone_from_slice()`, an efficient way to copy the data from one slice + and put it into another slice. +* Various convenience methods on `Ipv4Addr` and `Ipv6Addr`, such as `is_loopback()`, + which returns `true` or `false` if the address is a loopback address according to + RFC 6890. +* Various improvements to `CString`, used for FFI. +* checked, saturated, and overflowing operations for various numeric types. + These aren’t counted in that ‘40’ number above, because there are a _lot_ of + them, but they all do the same thing. + +See the [detailed release notes][notes] for more. + +#### Cargo features + +There were a few small updates to Cargo: + +* [`cargo init`](https://github.com/rust-lang/cargo/pull/2081) can be used to + start a Cargo project in your current working directory, rather than making a + new subdirectory like `cargo new`. +* `Cargo.toml` now has [keys for `-v` and `--color`](https://github.com/rust-lang/cargo/pull/2397) + +See the release notes for the full list of changes. + +### Contributors to 1.7 + +We had 126 individuals contribute to 1.7. Thank you so much! + +* Aaron Turon +* Abhishek Chanda +* Adolfo Ochagavía +* Aidan Hobson Sayers +* Alan Somers +* Alejandro Wainzinger +* Aleksey Kladov +* Alex Burka +* Alex Crichton +* Amanieu d'Antras +* Andrea Canciani +* Andreas Linz +* Andrew Cantino +* Andrew Horton +* Andrew Paseltiner +* Andrey Cherkashin +* Angus Lees +* arcnmx +* Ariel Ben-Yehuda +* ashleysommer +* Benjamin Herr +* Валерий Лашманов +* Björn Steinbrink +* bors +* Brian Anderson +* Brian Bowman +* Christian Wesselhoeft +* Christopher Serr +* Corey Farwell +* Craig M. Brandenburg +* Cyryl Płotnicki-Chudyk +* Daniel J Rollins +* Dave Huseby +* David AO Lozano +* David Henningsson +* Devon Hollowood +* Dirk Gadsden +* Doug Goldstein +* Eduard Burtescu +* Eduard-Mihai Burtescu +* Eli Friedman +* Emanuel Czirai +* Erick Tryzelaar +* Evan +* Felix S. Klock II +* Florian Berger +* Geoff Catlin +* ggomez +* gohyda +* Gökhan Karabulut +* Guillaume Gomez +* ituxbag +* James Miller +* Jeffrey Seyfried +* John Talling +* Jonas Schievink +* Jonathan S +* Jorge Aparicio +* Joshua Holmer +* JP Sugarbroad +* Kai Noda +* Kamal Marhubi +* Katze +* Kevin Brothaler +* Kevin Butler +* Manish Goregaokar +* Markus Westerlind +* Marvin Löbel +* Masood Malekghassemi +* Matt Brubeck +* Michael Huynh +* Michael Neumann +* Michael Woerister +* mitaa +* Ms2ger +* Nathan Kleyn +* nicholasf +* Nick Cameron +* Niko Matsakis +* Noah +* NODA, Kai +* Novotnik, Petr +* Oliver Middleton +* Oliver Schneider +* petevine +* Philipp Oppermann +* pierzchalski +* Piotr Czarnecki +* pravic +* Pyfisch +* Richo Healey +* Ruud van Asseldonk +* Scott Olson +* Sean McArthur +* Sebastian Wicki +* Sébastien Marie +* Seo Sanghyeon +* Simonas Kazlauskas +* Simon Sapin +* srinivasreddy +* Steve Klabnik +* Steven Allen +* Steven Fackler +* Stu Black +* Tang Chenglong +* Ted Horst +* Ticki +* tiehuis +* Tim Montague +* Tim Neumann +* Timon Van Overveldt +* Tobias Bucher +* Tobias Müller +* Todd Lucas +* Tom Tromey +* Tshepang Lekhonkhobe +* ubsan +* Ulrik Sverdrup +* Vadim Petrochenkov +* vagrant +* Valentin Lorentz +* Varun Vats +* vegai +* vlastachu +* Wangshan Lu +* York Xiang From 3d20499b8a2c6fdb5bc5724328b4764d607c02cf Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 14 Apr 2016 11:38:48 -0400 Subject: [PATCH 210/386] fixes per feedback --- _posts/2016-04-14-Rust-1.8.md | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md index ed584e3fe..1223f1ef9 100644 --- a/_posts/2016-04-14-Rust-1.8.md +++ b/_posts/2016-04-14-Rust-1.8.md @@ -59,19 +59,18 @@ The second feature is very small, and comes from [RFC 218]. Before Rust 1.8, a ```rust struct Foo; // works -struct Bar { }; // error +struct Bar { } // error ``` [RFC 218]: https://github.com/rust-lang/rfcs/blob/master/text/0218-empty-struct-with-braces.md -The second form is no longer an error, and is equivalent to the first. This was +The second form is no longer an error. This was originally disallowed for consistency with other empty declarations, as well as a parsing ambiguity. However, that ambiguity is non-existent in post-1.0 Rust, and macro authors saw additional complexity due to needing a special-case. Also, users who do active development would sometimes switch between empty and non-empty versions of a struct, and the extra work and diffs involved was less -than ideal. Allowing both forms is slightly less consistent, but the ergonomics -of these two cases was deemed worth it. +than ideal. On the Windows front, 32-bit MSVC builds [now implement unwinding]. This moves `i686-pc-windows-msvc` to a Tier 1 platform. @@ -85,7 +84,7 @@ and based on Cargo. It is not yet the default, and there is much more work to do. We will talk about this in release notes more once it’s completely done, for now, please read the GitHub issue for more details. -[initial support landed]: https://github.com/rust-lang/rust/pull/30448 +[initial support landed]: https://github.com/rust-lang/rust/pull/31123 #### Library stabilizations @@ -110,18 +109,24 @@ See the [detailed release notes][notes] for more. #### Cargo features -There were a few small updates to Cargo: +There were a few updates to Cargo: * [`cargo init`](https://github.com/rust-lang/cargo/pull/2081) can be used to start a Cargo project in your current working directory, rather than making a new subdirectory like `cargo new`. -* `Cargo.toml` now has [keys for `-v` and `--color`](https://github.com/rust-lang/cargo/pull/2397) +* [`cargo metadata`](https://github.com/rust-lang/cargo/pull/2196) is another + new subcommand for fetching metadata about a project. +* `.cargo/config` now has [keys for `-v` and + `--color`](https://github.com/rust-lang/cargo/pull/2397) +* Cargo’s ability to have target-specific dependencies [was + enhanced](https://github.com/rust-lang/cargo/pull/2328). -See the release notes for the full list of changes. -### Contributors to 1.7 +See the [detailed release notes][notes] for more. + +### Contributors to 1.8 -We had 126 individuals contribute to 1.7. Thank you so much! +We had 126 individuals contribute to 1.8. Thank you so much! * Aaron Turon * Abhishek Chanda From 5c59207c69942f641cadc080b9547bd1a85dd18c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 14 Apr 2016 13:12:54 -0400 Subject: [PATCH 211/386] small fixes --- _posts/2016-04-14-Rust-1.8.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md index 1223f1ef9..1ae8f592a 100644 --- a/_posts/2016-04-14-Rust-1.8.md +++ b/_posts/2016-04-14-Rust-1.8.md @@ -64,13 +64,13 @@ struct Bar { } // error [RFC 218]: https://github.com/rust-lang/rfcs/blob/master/text/0218-empty-struct-with-braces.md -The second form is no longer an error. This was -originally disallowed for consistency with other empty declarations, as well as -a parsing ambiguity. However, that ambiguity is non-existent in post-1.0 Rust, -and macro authors saw additional complexity due to needing a special-case. Also, -users who do active development would sometimes switch between empty and -non-empty versions of a struct, and the extra work and diffs involved was less -than ideal. +The second form is no longer an error. This was originally disallowed for +consistency with other empty declarations, as well as a parsing ambiguity. +However, that ambiguity is non-existent in post-1.0 Rust. Macro authors saw +additional complexity due to needing a special-case, as well. Finally, users +who do active development would sometimes switch between empty and non-empty +versions of a struct, and the extra work and diffs involved was less than +ideal. On the Windows front, 32-bit MSVC builds [now implement unwinding]. This moves `i686-pc-windows-msvc` to a Tier 1 platform. @@ -102,7 +102,7 @@ Other notable improvements include: RFC 6890. * Various improvements to `CString`, used for FFI. * checked, saturated, and overflowing operations for various numeric types. - These aren’t counted in that ‘40’ number above, because there are a _lot_ of + These aren’t counted in that ‘20’ number above, because there are a _lot_ of them, but they all do the same thing. See the [detailed release notes][notes] for more. From 75484d793f95cf7d1fd90266b867c996b8ec4f42 Mon Sep 17 00:00:00 2001 From: bluss Date: Thu, 14 Apr 2016 19:44:00 +0200 Subject: [PATCH 212/386] rm clone_from_slice (not this release). clone_from_slice was 1.7 (and copy_from_slice will be in 1.9) --- _posts/2016-04-14-Rust-1.8.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md index 1ae8f592a..026c32921 100644 --- a/_posts/2016-04-14-Rust-1.8.md +++ b/_posts/2016-04-14-Rust-1.8.md @@ -95,8 +95,6 @@ language section. Other notable improvements include: -* `<[T]>::clone_from_slice()`, an efficient way to copy the data from one slice - and put it into another slice. * Various convenience methods on `Ipv4Addr` and `Ipv6Addr`, such as `is_loopback()`, which returns `true` or `false` if the address is a loopback address according to RFC 6890. From a2537651877997887b8586aa6d165b7688c714d2 Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 14 Apr 2016 13:49:25 -0400 Subject: [PATCH 213/386] Gemfile fixes 1. the source should be set in the gemfile 2. the lock should be in source control --- Gemfile | 4 +- Gemfile.lock | 133 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 136 insertions(+), 1 deletion(-) create mode 100644 Gemfile.lock diff --git a/Gemfile b/Gemfile index c5d8e4676..825baa500 100644 --- a/Gemfile +++ b/Gemfile @@ -1 +1,3 @@ -gem 'github-pages' \ No newline at end of file +source "https://rubygems.org" + +gem 'github-pages' diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 000000000..b2258ed9e --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,133 @@ +GEM + remote: https://rubygems.org/ + specs: + RedCloth (4.2.9) + activesupport (4.2.6) + i18n (~> 0.7) + json (~> 1.7, >= 1.7.7) + minitest (~> 5.1) + thread_safe (~> 0.3, >= 0.3.4) + tzinfo (~> 1.1) + addressable (2.4.0) + coffee-script (2.4.1) + coffee-script-source + execjs + coffee-script-source (1.10.0) + colorator (0.1) + ethon (0.8.1) + ffi (>= 1.3.0) + execjs (2.6.0) + faraday (0.9.2) + multipart-post (>= 1.2, < 3) + ffi (1.9.10) + gemoji (2.1.0) + github-pages (69) + RedCloth (= 4.2.9) + github-pages-health-check (= 1.1.0) + jekyll (= 3.0.3) + jekyll-coffeescript (= 1.0.1) + jekyll-feed (= 0.4.0) + jekyll-gist (= 1.4.0) + jekyll-github-metadata (= 1.11.0) + jekyll-mentions (= 1.1.2) + jekyll-paginate (= 1.1.0) + jekyll-redirect-from (= 0.10.0) + jekyll-sass-converter (= 1.3.0) + jekyll-seo-tag (= 1.3.3) + jekyll-sitemap (= 0.10.0) + jekyll-textile-converter (= 0.1.0) + jemoji (= 0.6.2) + kramdown (= 1.10.0) + liquid (= 3.0.6) + mercenary (~> 0.3) + rdiscount (= 2.1.8) + redcarpet (= 3.3.3) + rouge (= 1.10.1) + terminal-table (~> 1.4) + github-pages-health-check (1.1.0) + addressable (~> 2.3) + net-dns (~> 0.8) + octokit (~> 4.0) + public_suffix (~> 1.4) + typhoeus (~> 0.7) + html-pipeline (2.4.0) + activesupport (>= 2, < 5) + nokogiri (>= 1.4) + i18n (0.7.0) + jekyll (3.0.3) + colorator (~> 0.1) + jekyll-sass-converter (~> 1.0) + jekyll-watch (~> 1.1) + kramdown (~> 1.3) + liquid (~> 3.0) + mercenary (~> 0.3.3) + rouge (~> 1.7) + safe_yaml (~> 1.0) + jekyll-coffeescript (1.0.1) + coffee-script (~> 2.2) + jekyll-feed (0.4.0) + jekyll-gist (1.4.0) + octokit (~> 4.2) + jekyll-github-metadata (1.11.0) + octokit (~> 4.0) + jekyll-mentions (1.1.2) + html-pipeline (~> 2.3) + jekyll (~> 3.0) + jekyll-paginate (1.1.0) + jekyll-redirect-from (0.10.0) + jekyll (>= 2.0) + jekyll-sass-converter (1.3.0) + sass (~> 3.2) + jekyll-seo-tag (1.3.3) + jekyll (~> 3.0) + jekyll-sitemap (0.10.0) + jekyll-textile-converter (0.1.0) + RedCloth (~> 4.0) + jekyll-watch (1.3.1) + listen (~> 3.0) + jemoji (0.6.2) + gemoji (~> 2.0) + html-pipeline (~> 2.2) + jekyll (>= 3.0) + json (1.8.3) + kramdown (1.10.0) + liquid (3.0.6) + listen (3.0.6) + rb-fsevent (>= 0.9.3) + rb-inotify (>= 0.9.7) + mercenary (0.3.6) + mini_portile2 (2.0.0) + minitest (5.8.4) + multipart-post (2.0.0) + net-dns (0.8.0) + nokogiri (1.6.7.2) + mini_portile2 (~> 2.0.0.rc2) + octokit (4.3.0) + sawyer (~> 0.7.0, >= 0.5.3) + public_suffix (1.5.3) + rb-fsevent (0.9.7) + rb-inotify (0.9.7) + ffi (>= 0.5.0) + rdiscount (2.1.8) + redcarpet (3.3.3) + rouge (1.10.1) + safe_yaml (1.0.4) + sass (3.4.22) + sawyer (0.7.0) + addressable (>= 2.3.5, < 2.5) + faraday (~> 0.8, < 0.10) + terminal-table (1.5.2) + thread_safe (0.3.5) + typhoeus (0.8.0) + ethon (>= 0.8.0) + tzinfo (1.2.2) + thread_safe (~> 0.1) + +PLATFORMS + ruby + +DEPENDENCIES + github-pages + +BUNDLED WITH + 1.11.2 From 875fda0eee8dcdbc1ef71a48b56d628a4f74472c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 14 Apr 2016 13:49:58 -0400 Subject: [PATCH 214/386] Set proper highlighter https://help.github.com/articles/page-build-failed-config-file-error/#fixing-highlighting-errors --- _config.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_config.yml b/_config.yml index 184e02dbe..151d76c9b 100644 --- a/_config.yml +++ b/_config.yml @@ -9,7 +9,7 @@ twitter_username: rustlang github_username: rust-lang # Build settings -highlighter: pygments +highlighter: rouge markdown: redcarpet redcarpet: extensions: ["with_toc_data", "smart"] From bb87079fd44838f002cb0860ce0cfe17bbb7d30a Mon Sep 17 00:00:00 2001 From: Simon Bernier St-Pierre Date: Thu, 14 Apr 2016 14:06:43 -0400 Subject: [PATCH 215/386] remove extra space before AddAssign --- _posts/2016-04-14-Rust-1.8.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md index 026c32921..96e064e97 100644 --- a/_posts/2016-04-14-Rust-1.8.md +++ b/_posts/2016-04-14-Rust-1.8.md @@ -25,7 +25,7 @@ and `-=`, are now overloadable via various traits. This change was accepted in [RFC 953], and looks like this: ```rust -use std::ops:: AddAssign; +use std::ops::AddAssign; #[derive(Debug)] struct Count { From 3aa6c46224937c7c70dfaaea9bcf80faa6f5409c Mon Sep 17 00:00:00 2001 From: Steve Klabnik Date: Thu, 14 Apr 2016 14:09:49 -0400 Subject: [PATCH 216/386] This is just wrong? --- _posts/2016-04-14-Rust-1.8.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/_posts/2016-04-14-Rust-1.8.md b/_posts/2016-04-14-Rust-1.8.md index 026c32921..a67ac74a3 100644 --- a/_posts/2016-04-14-Rust-1.8.md +++ b/_posts/2016-04-14-Rust-1.8.md @@ -93,16 +93,6 @@ major groups of changes: UTF-16 related string methods, various APIs related to time, and the various traits needed for operator overloading mentioned in the language section. -Other notable improvements include: - -* Various convenience methods on `Ipv4Addr` and `Ipv6Addr`, such as `is_loopback()`, - which returns `true` or `false` if the address is a loopback address according to - RFC 6890. -* Various improvements to `CString`, used for FFI. -* checked, saturated, and overflowing operations for various numeric types. - These aren’t counted in that ‘20’ number above, because there are a _lot_ of - them, but they all do the same thing. - See the [detailed release notes][notes] for more. #### Cargo features From f68bf1392dbfb1faee660ded98ec7ac2dc6515e7 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Tue, 19 Apr 2016 17:16:41 -0400 Subject: [PATCH 217/386] add a new blog post introducing MIR --- _posts/2016-04-19-MIR.md | 637 ++++++++++++++++++++++++++ images/2016-04-MIR/cfg.svg | 3 + images/2016-04-MIR/drop-unwind.svg | 3 + images/2016-04-MIR/drop.svg | 3 + images/2016-04-MIR/flow.svg | 3 + images/2016-04-MIR/loop-break.svg | 3 + images/2016-04-MIR/nzd-flags.svg | 3 + images/2016-04-MIR/nzd.svg | 3 + images/2016-04-MIR/send_if2-flags.svg | 3 + images/2016-04-MIR/send_if2-opt.svg | 3 + images/2016-04-MIR/send_if2.svg | 3 + 11 files changed, 667 insertions(+) create mode 100644 _posts/2016-04-19-MIR.md create mode 100644 images/2016-04-MIR/cfg.svg create mode 100644 images/2016-04-MIR/drop-unwind.svg create mode 100644 images/2016-04-MIR/drop.svg create mode 100644 images/2016-04-MIR/flow.svg create mode 100644 images/2016-04-MIR/loop-break.svg create mode 100644 images/2016-04-MIR/nzd-flags.svg create mode 100644 images/2016-04-MIR/nzd.svg create mode 100644 images/2016-04-MIR/send_if2-flags.svg create mode 100644 images/2016-04-MIR/send_if2-opt.svg create mode 100644 images/2016-04-MIR/send_if2.svg diff --git a/_posts/2016-04-19-MIR.md b/_posts/2016-04-19-MIR.md new file mode 100644 index 000000000..ba92501df --- /dev/null +++ b/_posts/2016-04-19-MIR.md @@ -0,0 +1,637 @@ +--- +layout: post +title: "Introducing MIR" +author: Niko Matsakis +description: "The shift to use MIR in the compiler should unlock many exciting improvements." +--- + +We are in the final stages of a grand transformation on the Rust +compiler internals. Over the past year or so, we have been steadily +working on a plan to change our internal compiler pipeline, as shown +here: + +
+![Compiler Flowchart][flow] +
+ +That is, we are introducing a new intermediate representation (IR) of +your program that we call **MIR**: MIR stands for *mid-level* IR, because +the MIR comes between the existing HIR ("high-level IR", roughly an +[abstract syntax tree][ast]) and [LLVM][llvm] (the "low-level" +IR). Previously, the "translation" phase in the compiler would convert +from full-blown Rust into machine-code-like LLVM in one rather large +step. But now, it will do its work in two phases, with a vastly +simplified version of Rust -- MIR -- standing in the middle. + +If you're not a compiler enthusiast, this all might seem arcane and unlikely to +affect you directly. But in reality, **MIR is the key to ticking off a number of +our highest priorities** for Rust: + +- **Faster compilation time**. We are working to make Rust's compilation + *incremental*, so that when you *re*-compile code, the compiler recomputes only + what it has to. MIR has been designed from the start with this use-case in mind, + so it's much easier for us to save and reload, even if other parts of the program + have changed in the meantime. + + MIR also provides a foundation for more efficient data structures and removal + of redundant work in the compiler, both of which should speed up compilation + across the board. + +- **Faster execution time**. You may have noticed that in the new compiler + pipeline, *optimization* appears twice. That's no accident: previously, the + compiler relied solely on LLVM to perform optimizations, but with MIR, we can + do some *Rust-specific* optimizations before ever hitting LLVM -- or, for that + matter, before monomorphizing code. Rust's rich type system should provide + fertile ground for going beyond LLVM's optimizations. + + In addition, MIR will uncork some longstanding performance improvements + to the code Rust generates, like ["non-zeroing" drop][rfc320]. + +- **More precise type checking**. Today's Rust compiler imposes some + artificial restrictions on *borrowing*, restrictions which largely + stem from the way the compiler currently represents programs. MIR + will enable [much more flexible borrowing][811], which will in turn + improve Rust's ergonomics and learning curve. + +Beyond these banner user-facing improvements, **MIR also has substantial +engineering benefits for the compiler**: + +- **Eliminating redundancy.** Currently, because we write all of our passes in + terms of the full Rust language, there is quite a lot of duplication. For + example, both the safety analyses and the backend which produces LLVM IR must + agree about how to translate drops, or the precise order in which `match` + expression arms will be tested and executed (which can get quite + complex). With MIR, all of that logic is centralized in MIR construction, and + the later passes can just rely on that. + +- **Raising ambitions.** In addition to being more [DRY][dry], working + with MIR is just plain *easier*, because it contains a much more + primitive set of operations than ordinary Rust. This simplification + enables us to do a lot of things that were forbodingly complex + before. We'll look at one such case in this post -- non-zeroing + drop -- but as we'll see at the end, there are already many others + in the pipeline. + +Needless to say, we're excited, and the Rust community has stepped up +in a big way to make MIR a reality. The compiler can bootstrap and run +its test suite using MIR, and these tests have to pass on every new +commit. Once we're able to run [Crater][crater] with MIR enabled and +see no regressions across the entire [crates.io](http://crates.io/) +ecosystem, we'll turn it on by default (or, you'll forgive a terrible +(wonderful) pun, [launch MIR into orbit][orbit]). + +This blog post begins with an overview of MIR's design, demonstrating +some of the ways that MIR is able to abstract away the full details of +the Rust language. Next, we look at how MIR will help with +implementing [non-zeroing drops][rfc320], a long-desired +optimization. If after this post you find you are hungry for more, +have a look at the [RFC that introduced MIR][rfc1211], or jump right +into [the code][]. (Compiler buffs may be particularly interested in +the [alternatives section][alt], which discusses certain design +choices in detail, such as why MIR does not currently use SSA.) + + + +### Reducing Rust to a simple core + +MIR reduces Rust down to a simple core, removing almost all of the +Rust syntax that you use every day, such as `for` loops, `match` +expressions, and even method calls. Instead, those constructs are +translated to a small set of primitives. This does not mean that MIR +is a *subset* of Rust. As we'll see, many of these primitives +operations are not available in real Rust. This is because those +primitives could be misused to write unsafe or undesirable programs. + +The simple core language that MIR supports is not something you would +want to program in. In fact, it makes things almost painfully +explicit. But it's great if you want to write a type-checker or +generate assembly code, as you now only have to handle the core +operations that remain after MIR translation. + +To see what I mean, let's start by simplifying a fragment of Rust code. +At first, we'll just break the Rust down into "simpler Rust", but +eventually we'll step away from Rust altogether and into MIR code. + +Our Rust example starts out as this simple `for` loop, which iterates +over all the elements in a vector and processes them one by one: + +```rust +for elem in vec { + process(elem); +} +``` + +Rust itself offers three kinds of loops: `for` loops, like this one; +`while` and `while let` loops, that iterate until some condition is +met; and finally the simple `loop`, which just iterates until you +break out of it. Each of these kinds of loops encapsulates a +particular pattern, so they are quite useful when writing code. But +for MIR, we'd like to reduce all of these into one core concept. + +A `for` loop in Rust works by converting a value into an iterator and +then repeatedly calling `next` on that iterator. That means that we +can rewrite the `for` loop we saw before into a `while let` loop +that looks like this: + +```rust +let mut iterator = vec.into_iter(); +while let Some(elem) = iterator.next() { + process(elem); +} +``` + +By applying this rewriting, we can remove all `for` loops, but that +still leaves multiple kinds of loops. So next we can imagine rewrite +all `while let` loops into a simple `loop` combined with a `match`: + +```rust +let mut iterator = vec.into_iter(); +loop { + match iterator.next() { + Some(elem) => process(elem), + None => break, + } +} +``` + +We've already eliminated two constructs (`for` loops and `while` +loops), but we can go further still. Let's turn from loops for a bit +to look at the method calls that we see. In Rust, method calls like +`vec.into_iter()` and `iterator.next()` are also a kind of +[syntactic sugar][ss]. These particular methods are defined in traits, +which are basically pre-defined interfaces. For example, `into_iter` +is a method in the `IntoIterator` trait. Types which can be converted +into iterators implement that trait and define how the `into_iter` +method works for them. Similarly, `next` is defined in the `Iterator` +trait. When you write a method call like `iterator.next()`, the Rust +compiler automatically figures out which trait the method belongs to +based on the type of the `iterator` and the set of traits in +scope. But if we prefer to be more explicit, we could instead invoke +the methods in the trait directly, using function call syntax: + +```rust +// Rather than `vec.into_iter()`, we are calling +// the function `IntoIterator::into_iter`. This is +// exactly equivalent, just more explicit. +let mut iterator = IntoIterator::into_iter(vec); +loop { + // Similarly, `iterator.next()` can be rewritten + // to make clear which trait the `next` method + // comes from. We see here that the `.` notation + // was also adding an implicit mutable reference, + // which is now made explicit. + match Iterator::next(&mut iterator) { + Some(elem) => process(elem), + None => break, + } +} +``` + +At this point, we've managed to reduce the set of language features +for our little fragment quite a bit: we now only use `loop` loops and +we don't use method calls. But we could reduce the set of concepts +further if were moved away from `loop` and `break` and towards +something more fundamental: `goto`. Using `goto` we could transform +the previous code example into something like this: + +```rust + let mut iterator = IntoIterator::into_iter(vec); + +loop: + match Iterator::next(&mut iterator) { + Some(elem) => { process(elem); goto loop; } + None => { goto break; } + } + +break: + ... +``` + +We've gotten pretty far in breaking our example down into simpler +constructs. We're not quite done yet, but before we go further it's +worth stepping back a second to make a few observations: + +**Some MIR primitives are more powerful than the structured construct +they replace.** Introducing the `goto` keyword is a big simplification +in one sense: it unifies and replaces a large number of control-flow +keywords. `goto` completely replaces `loop`, `break`, `continue`, but +it also allows us to simplify `if` and `match` as well (we'll see more +on `match` in particular in a bit). However, this simplification is +only possible because `goto` is a *more general* construct than +`loop`, and it's something we would not want to introduce into the +language proper, because we don't want people to be able to write +spaghetti-like-code with complex control-flow that is hard to read and +follow later. But it's fine to have such a construct in MIR, because +we know that it will only be used in particular ways, such as to +express a `loop` or a `break`. + +**MIR construction is type-driven.** We saw that all method calls like +`iterator.next()` can be desugared into fully qualified function calls +like `Iterator::next(&mut iterator)`. However, doing this rewrite is +only possible with full type information, since we must (for example) +know the type of `iterator` to determine which trait the `next` method +comes from. In general, constructing MIR is only possible after +type-checking is done. + +**MIR makes all types explicit.** Since we are constructing MIR after +the main type-checking is done, MIR can include full type +information. This is useful for analyses like the borrow checker, +which require the types of local variables and so forth to operate, +but also means we can run the type-checker periodically as a kind of +sanity check to ensure that the MIR is well-formed. + +### Control-flow graphs + +In the previous section, I presented a gradual "deconstruction" of a +Rust program into something resembling MIR, but we stayed in textual +form. Internally to the compiler, though, we represent MIR as a +[control-flow graph (CFG)][CFG]. If you've ever used a flow-chart, +then the concept of a control-flow graph will be pretty familiar to +you. It's a representation of your program that exposes the underlying +control flow in a very clear way. + +A control-flow graph is structured as a set of basic blocks connected +by edges. Each basic block contains a sequence of statements and ends +in a *terminator*, which defines how the blocks are connected to one +another. When using a control-flow graph, a loop simply appears as a +cycle in the graph, and the `break` keyword translates into a path out +of that cycle. + +Here is the running example from the previous section, expressed as a +control-flow graph: + +
+![Control-flow-graph][cfg] +
+ +Building a control-flow graph is typically a first step for any kind +of flow-sensitive analysis. It's also a natural match for LLVM IR, +which is also structured into control-flow graph form. The fact that +MIR and LLVM correspond to one another fairly closely makes +translation quite straight-forward. It also eliminates a vector for +bugs: in today's compiler, the control-flow graph used for analyses is +not necessarily the same as the one which results from LLVM +construction, which can lead to incorrect programs being accepted. + +### Simplifying match expressions + +The example in the previous section showed how we can reduce all of +Rust's loops into, effectively, gotos in the MIR and how we can remove +methods calls in favor of calls to explicit calls to trait +functions. But it glossed over one detail: **match expressions**. + +One of the big goals in MIR was to simplify match expressions into a +very small core of operations. We do this by introducing two +constructs that the main language does not include: *switches* and +*variant downcasts*. Like `goto`, these are things that we would not +want in the base language, because they can be misused to write bad +code; but they are perfectly fine in MIR. + +It's probably easiest to explain match handling by example. Let's +consider the `match` expression we saw in the previous section: + +```rust +match Iterator::next(&mut iterator) { + Some(elem) => process(elem), + None => break, +} +``` + +Here, the result of calling `next` is of type `Option`, where `T` +is the type of the elements. The `match` expression is thus doing two +things: first, it is determining whether this `Option` was a value +with the `Some` or `None` variant. Then, in the case of the `Some` +variant, it is extracting the value `elem` out. + +In normal Rust, these two operations are intentionally coupled, +because we don't want you to read the data from an `Option` unless it +has the `Some` variant (to do otherwise would be effectively a C +union, where reads are not checked for correctness). + +In MIR, though, we separate the checking of the variant from the +extracting of the data. I'm going to give the equivalent of MIR here +first in a kind of pseudo-code, since there is no actual Rust syntax +for these operations: + +```rust +loop: + // Put the value we are matching on into a temporary variable. + let tmp = Iterator::next(&mut iterator); + + // Next, we "switch" on the value to determine which it has. + switch tmp { + Some => { + // If this is a sum, we can extract the element out + // by "downcasting", this effectively asserts that + // the value `tmp` is of the Some variant. + let elem = (tmp as Some).0; + + // The user's original code: + process(elem); + + goto loop; + } + None => { + goto break; + } + } + +break: + .... +``` + +Of course, the actual MIR is based on a control-flow-graph, so it +would look something like this: + +
+![Loop-break control-flow graph][loop-break] +
+ +### Explicit drops and panics + +So now we've seen how we can remove loops, method calls, and matches +out of the MIR, and replace them with simpler equivalents. But there +is still one key area that we can simplify. Interestingly, it's +something that happens almost invisibly in the code today: running +destructors and cleanup in the case of a panic. + +In the example control-flow-graph we saw before, we were assuming that +all of the code would execute successfully. But in reality, we can't +know that. For example, any of the function calls that we see could +panic, which would trigger the start of unwinding. As we unwind the +stack, we would have to run destructors for any values we +find. Figuring out precisely which local variables should be freed at +each point of panic is actually somewhat complex, so we would like to +make it explicit in the MIR: this way, MIR construction has to figure +it out, but later passes can just rely on the MIR. + +The way we do this is two-fold. First, we make *drops* explicit in the +MIR. Drop is the term we use for running the destructor on a value. In +MIR, whenever control-flow passes a point where a value should be +dropped, we add in a special `drop(...)` operation. Second, we add +explicit edges in the control-flow graph to represent potential +panics, and the cleanup that we have to do. + +Let's look at the explicit drops first. If you recall, we started with +an example that was just a for loop: + +```rust +for elem in vec { + process(elem); +} +``` + +We then transformed this for loop to explicitly invoke +`IntoIterator::into_iter(vec)`, yielding a value `iterator`, from +which we extract the various elements. Well, this value `iterator` +actually has a destructor, and it will need to be freed (in this case, +its job is to free the memory that was used by the vector `vec`; this +memory is no longer needed, since we've finished iterating over the +vector). Using the `drop` operation, we can adjust our MIR +control-flow-graph to show explicitly where the `iterator` value gets +freed. Take a look at the new graph, and in particular what happens +when a `None` variant is found: + +
+![Drop control-flow graph][drop] +
+ +Here we see that, when the loop exits normally, we will drop the +iterator once it has finished. But what about if a panic occurs? Any +of the function calls we see here could panic, after all. To account +for that, we introduce panic edges into the graph: + +
+![Panic control-flow graph][drop-unwind] +
+ +Here we have introduced `panic` edges onto each of the function +calls. By looking at these edges, you can see that the if the call to +`next` or `process` should panic, then we will drop the variable +`iterator`; but if the call to `into_iter` panics, the the `iterator` +hasn't been initialized yet, so it should not be dropped. + +One interesting wrinkle: we recently approved [RFC 1513][rfc1513], +which allows an application to specify that panics should be treated +as calls to `abort`, rather than triggering unwinding. If the program +is being compiled with "panic as abort" semantics, then this too would +be reflected in the MIR, as the panic edges and handling would simply +be absent from the graph. + +### Viewing MIR on play + +At this point, we've reduced our example into something fairly close +to what MIR actually looks like. If you'd like to see for yourself, +you can [view the MIR for our example](http://is.gd/MOfDfg) on +[play.rust-lang.org](https://play.rust-lang.org/). Just +[follow this link](http://is.gd/MOfDfg) and then press the "MIR" +button along the top. You'll wind up seeing the MIR for several +functions, so you have to search through to find the start of the +`example` fn. (I won't reproduce the output here, as it is fairly +lengthy.) In the compiler itself, you can also enable graphviz output. + +### Drops and stack flags + +By now I think you have a feeling for how MIR represents a simplified +Rust. Let's look at one example of where MIR will allow us to +implement a long-awaited improvement to Rust: the shift to non-zeroing +drop. This is a change to how we detect when destructors must execute, +particularly when values are only *sometimes* moved. This move was +proposed (and approved) in [RFC 320][rfc320], but it has yet to be +implemented. This is primarily because doing it on the pre-MIR +compiler was architecturally challenging. + +To better understand what the feature is, consider this function +`send_if`, which conditionally sends a vector to another thread: + +```rust +fn send_if(data: Vec) { + // If `some_condition` returns *true*, then ownership of `data` + // moves into the `send_to_other_thread` function, and hence + // we should not free it (the other thread will free it). + if some_condition(&data) { + send_to_other_thread(data); + } + + post_send(); + + // If `some_condition` returned *false*, the ownership of `data` + // remains with `send_if`, which means that the `data` vector + // should be freed here, when we return. +} +``` + +The key point, as indicated in the comments, is that we can't know +statically whether we ought to free `data` or not. It depends on +whether we entered the `if` or not. + +To handle this scenario today, the compiler uses *zeroing*. Or, more +accurately, *overwriting*. What this means is that, if ownership of +`data` is moved, we will overwrite the stack slot for `data` with a +specific, distinctive bit pattern that is not a valid pointer (we used +to use zeroes, so we usually call this zeroing, but we've since +shifted to something different). Then, when it's time to free `data`, +we check whether it was overwritten. (As an aside, this is roughly the +same thing that the equivalent C++ code would do.) + +But we'd like to do better than that. What we would *like* to do is to +use boolean flags on the stack that tell us what needs to be freed. +So that might look something like this: + +```rust +fn send_if(data: Vec) { + let mut data_is_owned = true; + + if some_condition(&data) { + send_to_other_thread(data); + data_is_owned = false; + } + + post_send(); + + // Free `data`, but only if we still own it: + if data_is_owned { + mem::drop(data); + } +} +``` + +Of course, you couldn't write code like this in Rust. You're not +allowed to acccess the variable `data` after the `if`, since it might +have been moved. (This is yet another example of where we can do +things in MIR that we would not want to allow in full Rust.) + +Using boolean stack flags like this has a lot of advantages. For one, +it's more efficient: instead of overwriting the entire vector, we only +have to set the one flag. But also, it's easier to optimize: imagine +that, through inlining or some other means, the compiler was able to +determine that `some_condition` would always be true. In that case, +standard constant propagation techniques would tell us that +`data_is_owned` is always false, and hence we can just optimize away +the entire call to `mem::drop`, resulting in tighter code. See +[RFC 320][rfc320] for more details on that. + +However, implementing this optimization properly on the current +compiler architecture is quite difficult. With MIR, it becomes +relatively straightforward. The MIR control-flow-graph tells us +explicitly where values will be dropped and when. When MIR is first +generated, we assume that dropping moved data has no effect -- roughly +like the current overwriting semantics. So this means that the MIR for +`send_if` might look like this (for simplicity, I'll ignore unwinding +edges). + +
+![Non-zeroing drop example][nzd] +
+ +We can then transform this graph by identifying each place where +`data` is moved or dropped and checking whether any of those places +can reach one another. In this case, the `send_to_other_thread(data)` block can +reach `drop(data)`. This indicates that we will need to introduce a +flag, which can be done rather mechanically: + +
+![Non-zeroing drop with flags][nzd-flags] +
+ +Finally, we can apply standard compiler techniques to optimize this +flag (but in this case, the flag is needed, and so the final result +would be the same). + +Just to drive home why MIR is useful, let's consider a variation on +the `send_if` function called `send_if2`. This variation checks some +condition and, if it is met, sends the data to another thread for +processing. Otherwise, it processes it locally: + +```rust +fn send_if2(data: Vec) { + if some_condition(&data) { + send_to_other_thread(data); + return; + } + + process(&data); +} +``` + +This would generate MIR like: + +
+![Control-flow graph for send_if2][send_if2] +
+ +As before, we still generate the drops of `data` in all cases, at +least to start. Since there are still moves that can later reach a +drop, we could now introduce a stack flag variable, just as before: + +
+![send_if2 with flags][send_if2-flags] +
+ +But in this case, if we apply constant propagation, we can see that at +each point where we test `data_is_owned`, we know statically whether +it is true or false, which would allow us to remove the stack flag and +optimize the graph above, yielding this result: + +
+![Optimized send_if2][send_if2-opt] +
+ +### Conclusion + +I expect the use of MIR to be quite transformative in terms of what +the compiler can accomplish. By reducing the language to a core set of +primitives, MIR opens the door to a number of language improvements. +We looked at drop flags in this post. Another example is improving +Rust's lifetime system to +[leverage the control-flow-graph for better precision][811]. But I +think there will be many applications that we haven't foreseen. In +fact, one such example has already arisen: Scott Olson has been making +great strides developing a MIR interpreter [miri][], and the +techniques it is exploring may well form the basis for a more powerful +constant evaluator in the compiler itself. + +The transition to MIR in the compiler is not yet complete, but it's +getting quite close. Special thanks go out to Simonas Kazlauskas +([nagisa][]) and Eduard-Mihai Burtescu ([eddyb][]), who have both had +a particularly large impact on pushing MIR towards the finish +line. Our initial goal is to switch our LLVM generation to operate +exclusively from the MIR. Work is also proceeding on porting the +borrow checker. After that, I expect we will port a number of other +pieces on the compiler that are currently using the HIR. If you'd be +interested in contributing, look for +[issues tagged with `A-mir`][issues] or ask around in the +[`#rustc` channel on IRC][community]. + +[rfc320]: https://github.com/rust-lang/rfcs/blob/master/text/0320-nonzeroing-dynamic-drop.md +[rfc1513]: https://github.com/rust-lang/rfcs/blob/master/text/1513-less-unwinding.md +[issues]: https://github.com/rust-lang/rust/issues?q=is%3Aopen+is%3Aissue+label%3AA-mir +[community]: https://www.rust-lang.org/community.html +[DRY]: https://en.wikipedia.org/wiki/Don%27t_repeat_yourself +[811]: https://github.com/rust-lang/rfcs/issues/811 +[miri]: https://github.com/tsion/miri +[rfc1211]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md +[ss]: https://en.wikipedia.org/wiki/Syntactic_sugar +[CFG]: https://en.wikipedia.org/wiki/Control_flow_graph +[AST]: https://en.wikipedia.org/wiki/Abstract_syntax_tree +[LLVM]: http://llvm.org/ +[the code]: https://github.com/rust-lang/rust/blob/master/src/librustc/mir/repr.rs +[orbit]: https://en.wikipedia.org/wiki/Mir +[crater]: https://github.com/brson/taskcluster-crater + +[pipeline]: https://gist.githubusercontent.com/nikomatsakis/d3942c970fc7b5dc2feee32ea4d5a00a/raw/8712369186243df6e5f156cdb61a16babc0ed464/z-2016-04-compiler-pipeline.jpg +[cfg1]: https://gist.githubusercontent.com/nikomatsakis/d3942c970fc7b5dc2feee32ea4d5a00a/raw/8712369186243df6e5f156cdb61a16babc0ed464/z-2016-04-cfg-match-1.jpg +[nagisa]: https://github.com/nagisa/ +[eddyb]: https://github.com/eddyb/ + +[cfg]: /images/2016-04-MIR/cfg.svg +[drop-unwind]: /images/2016-04-MIR/drop-unwind.svg +[drop]: /images/2016-04-MIR/drop.svg +[flow]: /images/2016-04-MIR/flow.svg +[loop-break]: /images/2016-04-MIR/loop-break.svg +[nzd-flags]: /images/2016-04-MIR/nzd-flags.svg +[nzd]: /images/2016-04-MIR/nzd.svg +[send_if2-flags]: /images/2016-04-MIR/send_if2-flags.svg +[send_if2-opt]: /images/2016-04-MIR/send_if2-opt.svg +[send_if2]: /images/2016-04-MIR/send_if2.svg +[alt]: https://github.com/rust-lang/rfcs/blob/master/text/1211-mir.md#alternatives diff --git a/images/2016-04-MIR/cfg.svg b/images/2016-04-MIR/cfg.svg new file mode 100644 index 000000000..a34cfeeb4 --- /dev/null +++ b/images/2016-04-MIR/cfg.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000cfgLayer 1iterator = IntoIterator::into_iter(vec)match IntoIterator::next(&mut iterator)process(elem)SomeNone(Loop Edge)(Break edge) diff --git a/images/2016-04-MIR/drop-unwind.svg b/images/2016-04-MIR/drop-unwind.svg new file mode 100644 index 000000000..96419d17d --- /dev/null +++ b/images/2016-04-MIR/drop-unwind.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000drop-unwindLayer 1iterator = IntoIterator::into_iter(vec)tmp = IntoIterator::next(&mut iterator)elem = (tmp as Some).0SomeNoneswitch tmpprocess(elem)drop(iterator)drop(iterator)panicpanicpanic diff --git a/images/2016-04-MIR/drop.svg b/images/2016-04-MIR/drop.svg new file mode 100644 index 000000000..6f1449e36 --- /dev/null +++ b/images/2016-04-MIR/drop.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000dropLayer 1iterator = IntoIterator::into_iter(vec)tmp = IntoIterator::next(&mut iterator)elem = (tmp as Some).0SomeNoneswitch tmpprocess(elem)drop(iterator) diff --git a/images/2016-04-MIR/flow.svg b/images/2016-04-MIR/flow.svg new file mode 100644 index 000000000..140475776 --- /dev/null +++ b/images/2016-04-MIR/flow.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000flowLayer 1Rust SourceHIRLLVM IRMachine CodeParsing and DesugaringBorrow checkingOptimizationType checkingTranslationRust SourceHIRLLVM IRMachine CodeParsing and DesugaringBorrow checkingOptimizationType checkingOptimizationMIRTodayTomorrow diff --git a/images/2016-04-MIR/loop-break.svg b/images/2016-04-MIR/loop-break.svg new file mode 100644 index 000000000..08f6f80fa --- /dev/null +++ b/images/2016-04-MIR/loop-break.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000loop-breakLayer 1iterator = IntoIterator::into_iter(vec)tmp = IntoIterator::next(&mut iterator)elem = (tmp as Some).0SomeNone...switch tmpprocess(elem) diff --git a/images/2016-04-MIR/nzd-flags.svg b/images/2016-04-MIR/nzd-flags.svg new file mode 100644 index 000000000..99d032247 --- /dev/null +++ b/images/2016-04-MIR/nzd-flags.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000nzd-flagsLayer 1if some_condition(&data)send_to_other_thread(data)post_send()if data_is_owned?returntruefalsedata_is_owned = truedata_is_owned = falsedrop(data)truefalse diff --git a/images/2016-04-MIR/nzd.svg b/images/2016-04-MIR/nzd.svg new file mode 100644 index 000000000..6059986d8 --- /dev/null +++ b/images/2016-04-MIR/nzd.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000nzdLayer 1if some_condition(&data)send_to_other_thread(data)post_send()drop(data)returntruefalse diff --git a/images/2016-04-MIR/send_if2-flags.svg b/images/2016-04-MIR/send_if2-flags.svg new file mode 100644 index 000000000..a0bbce564 --- /dev/null +++ b/images/2016-04-MIR/send_if2-flags.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000send_if2-flagsLayer 1if some_condition(&data)send_to_other_thread(data)process(&data)drop(data)returntruefalsedrop(data)data_is_owned = truedata_is_owned = falseif data_is_owned?truefalseif data_is_owned?truefalse diff --git a/images/2016-04-MIR/send_if2-opt.svg b/images/2016-04-MIR/send_if2-opt.svg new file mode 100644 index 000000000..eada858ac --- /dev/null +++ b/images/2016-04-MIR/send_if2-opt.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000send_if2-optLayer 1if some_condition(&data)send_to_other_thread(data)process(&data)drop(data)returntruefalse diff --git a/images/2016-04-MIR/send_if2.svg b/images/2016-04-MIR/send_if2.svg new file mode 100644 index 000000000..f46368e7a --- /dev/null +++ b/images/2016-04-MIR/send_if2.svg @@ -0,0 +1,3 @@ + + + Produced by OmniGraffle 6.5.2 2016-04-19 21:30:07 +0000send_if2Layer 1if some_condition(&data)send_to_other_thread(data)process(&data)drop(data)returntruefalsedrop(data) From 701fc1991b2524c20382564fae8d33e79f078423 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Wed, 27 Apr 2016 09:36:20 -0700 Subject: [PATCH 218/386] clarify data structure --- _posts/2016-04-19-MIR.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/_posts/2016-04-19-MIR.md b/_posts/2016-04-19-MIR.md index ba92501df..8840bd8aa 100644 --- a/_posts/2016-04-19-MIR.md +++ b/_posts/2016-04-19-MIR.md @@ -244,7 +244,9 @@ sanity check to ensure that the MIR is well-formed. In the previous section, I presented a gradual "deconstruction" of a Rust program into something resembling MIR, but we stayed in textual -form. Internally to the compiler, though, we represent MIR as a +form. Internally to the compiler, though, we never "parse" MIR or have +it in textual form. Instead, we represent MIR as a +[set of data structures][the code] encoding a [control-flow graph (CFG)][CFG]. If you've ever used a flow-chart, then the concept of a control-flow graph will be pretty familiar to you. It's a representation of your program that exposes the underlying From eb3d409370d9bfbc3ccd72007097e40e6769080b Mon Sep 17 00:00:00 2001 From: Benjamin Bouvier Date: Thu, 28 Apr 2016 11:34:36 +0200 Subject: [PATCH 219/386] Fix two typos in the MIR post; --- _posts/2016-04-19-MIR.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2016-04-19-MIR.md b/_posts/2016-04-19-MIR.md index 8840bd8aa..a176479fd 100644 --- a/_posts/2016-04-19-MIR.md +++ b/_posts/2016-04-19-MIR.md @@ -408,9 +408,9 @@ for that, we introduce panic edges into the graph: Here we have introduced `panic` edges onto each of the function -calls. By looking at these edges, you can see that the if the call to +calls. By looking at these edges, you can see that if the call to `next` or `process` should panic, then we will drop the variable -`iterator`; but if the call to `into_iter` panics, the the `iterator` +`iterator`; but if the call to `into_iter` panics, the `iterator` hasn't been initialized yet, so it should not be dropped. One interesting wrinkle: we recently approved [RFC 1513][rfc1513], From 3e004117dd92b4420f8c0e404b62105b5d5025ee Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Wed, 4 May 2016 16:45:09 -0700 Subject: [PATCH 220/386] Cargo pillars post --- _posts/2016-05-05-cargo-pillars.md | 489 +++++++++++++++++++++++++++++ 1 file changed, 489 insertions(+) create mode 100644 _posts/2016-05-05-cargo-pillars.md diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md new file mode 100644 index 000000000..29a35dced --- /dev/null +++ b/_posts/2016-05-05-cargo-pillars.md @@ -0,0 +1,489 @@ +--- +layout: post +title: "Cargo: predictable dependency management" +author: Yehuda Katz +description: "Cargo makes dependency management in Rust easy and predictable" +--- + +Cargo's goal is to make modern application package management a core value of +the Rust programming language. + +That concern is driven by a desire to answer questions like: + +1. If I want to use `libgit2` in my project, how easy is it? +2. If I build my project on a different machine, for a different architecture, + in CI or for release, am I building from the same source code? +3. If I build my project for testing, will my indirect dependencies be compiled + with debug symbols? If I build my project for release, will my indirect + dependencies be compiled with maximum optimizations? How can I be sure? +4. If someone published a new version of one of my dependencies after I commit, + will my CI environment use the same source code? My production environment? +5. If I add a new dependency (or upgrade one), can that break the build? Can it + affect unrelated dependencies? Under what conditions? + +**All of these questions (and many more like them) have one thing in common: +predictability**. One solution to this problem, common in the systems space, is +vendoring dependencies -- forking them directly into an application's repository +-- and then managing them manually. But this comes at a substantial per-project +cost, since there's more to manage. It also comes at an ecosystem-wide cost, +since there's less sharing. Making sure you can answer all of the questions +above, all of the time, is hard work. + +Package managers for higher-level languages have shown that by turning +dependency management over to a shared tool, you can have predictability, easy +workflows that operate over the entire dependency graph, and increased sharing +and robustness across the ecosystem. When we started planning Rust 1.0, we knew +we wanted to bring these ideas to a systems setting, and making Cargo a central +part of the way people use Rust was a big part of that. + +## Pillars of Cargo + +Cargo is built on three major pillars: + +1. Building, testing, and running projects should be predictable across + environments and over time. + +2. To the extent possible, indirect dependencies should be invisible to + application authors. + +3. Cargo should provide a shared workflow for the Rust ecosystem that aids the + first two goals. + +We'll look at each of these pillars in turn. + +## Predictability + +Cargo's predictability goals start with a simple guarantee: **once a +project successfully compiles, subsequent compiles will use exactly the same +source code, across machines and environments**. + +To achieve this guarantee, Cargo uses several strategies: + +1. The first time a build succeeds, Cargo emits a `Cargo.lock` file, which + contains a manifest of precisely which source code was used in the + build. (more on "precise" in a bit) + +2. Cargo manages the entire workflow, from running tests and benchmarks, to + building release artifacts, to running executables for debugging. This allows + Cargo to ensure that all dependencies (direct and indirect) are downloaded + and properly configured for these use-cases without the user having to do + anything extra. + +3. Cargo standardizes important environment configuration, like optimization + level, static and dynamic linking, and architecture. Combined with the + `Cargo.lock`, this makes the results of building, testing and executing Cargo + projects highly predictable. + +### Predictability By Example + +To illustrate these strategies, let's build an example crate using Cargo. To +keep things simple, we'll create a small `datetime` crate that exposes date and +time functionality. + +First, we'll use `cargo new` to start us out: + +``` +$ cargo new datetime +$ ls +Cargo.toml src +$ cat Cargo.toml +[package] +name = "datetime" +version = "0.1.0" +authors = ["Yehuda Katz "] + +[dependencies] +``` + +We don't want to build the date or time functionality from scratch, so let's +edit the `Cargo.toml` and add the `time` crate from crates.io: + +``` + [package] + name = "datetime" + version = "0.1.0" + authors = ["Yehuda Katz "] + + [dependencies] ++ time = "0.1.35" +``` + +Now that we've added the `time` crate, let's see what happens if we ask Cargo to +build our package: + +``` +$ cargo build + Compiling winapi v0.2.6 + Compiling libc v0.2.10 + Compiling winapi-build v0.1.1 + Compiling kernel32-sys v0.2.2 + Compiling time v0.1.35 + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) +``` + +Whoa! That's a lot of crates. **The biggest part of Cargo's job is to provide +enough predictability to allow functionality like the `time` crate to be broken +up into smaller crates that do one thing and do it well**. + +Now that we successfully built our crate, what happens if we try to build it again? + +``` +$ cargo build + +``` + +Nothing happened at all. Why's that? We can always ask Cargo to give us more +information through the `--verbose` flag, so let's do that: + +``` +$ cargo build --verbose + Fresh libc v0.2.10 + Fresh winapi v0.2.6 + Fresh winapi-build v0.1.1 + Fresh kernel32-sys v0.2.2 + Fresh time v0.1.35 + Fresh datetime v0.1.0 (file:///Users/ykatz/Code/datetime) +``` + +Cargo isn't bothering to recompile packages that it knows are "fresh". If you've +ever had to configure a `Makefile` before, this should be a breath of fresh air +(no pun intended). + +But how does Cargo know that everything is fresh? When Cargo builds a crate, it +emits a file called `Cargo.lock` that contains the precise versions of all of +its resolved dependencies: + +``` +[root] +name = "datetime" +version = "0.1.0" +dependencies = [ + "libc 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +... +``` + +The `Cargo.lock` contains a serialized version of the entire **resolved** +dependency graph, including precise versions of all of the source code included +in the build. In the case of a package from crates.io, Cargo stores the name and +version of the dependency. This is enough information to uniquely identify +source code from crates.io, because the registry is **append only** (no changes +to already-published packages are ever allowed). + +In addition, the metadata for the registry is stored in a separate git +repository, and includes checksum for the relevant package. Before Cargo ever +unpacks a crate it downloads, it first validates the checksum. + +Here's what the entry for `kernel32-sys 0.2.2` looks like: + +``` +{"name":"kernel32-sys","vers":"0.2.2","deps":[{"name":"winapi","req":"^0.2.5","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal"},{"name":"winapi-build","req":"^0.1.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"build"}],"cksum":"7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d","features":{},"yanked":false} +``` + +### Collaborating + +Now for the real test. Let's push our code up to GitHub and develop it on a +different machine. Ideally, we would like to be able to pick up right where we +left off, with the exact same source code for all of our dependencies. + +To do this, we check in our `Cargo.lock` and clone the repository on our new +machine. Then, we run `cargo build` again. + +``` +$ cargo build + Compiling libc v0.2.10 + Compiling winapi v0.2.6 + Compiling winapi-build v0.1.1 + Compiling kernel32-sys v0.2.2 + Compiling time v0.1.35 + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) +``` + +As expected, **because we checked in our `Cargo.lock` we get exactly the same +versions of all dependencies as before**. And if we wanted to start collaborating +with other developers on GitHub (or with other members of our team at work), we +would continue to get the same level of predictability. + +### Common conventions: examples and tests + +Now that we've written our snazzy new `datetime` crate, we'd love to write an +example to show other developers how it should be used. We create a new file +called `examples/date.rs` that looks like this: + +``` +extern crate datetime; + +fn main() { + println!("{}", datetime::DateTime::now()); +} +``` + +To run the example, we ask Cargo to build and run it: + +``` +$ cargo run --example date + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) + Running `target/debug/examples/date` +26 Apr 2016 :: 05:03:38 +``` + +Because we put our code in the conventional location for examples, Cargo knew +how to do the right thing, no sweat. + +In addition, once you start writing a few tests, `cargo test` will automatically +build your examples as well, which prevents them from getting out of sync with +your code, and ensures they continue to compile as long as your tests are +passing. + +These are just two examples of a general approach: **Cargo defines a common set of +conventions and workflows that operate precisely the same way across the entire +Rust ecosystem**. + +### Updating + +All of this means that your application won't change if you don't make any +changes to your dependencies, but what happens when you need to change them? + +Cargo adds another layer of protection with **conservative updates**. This means +that if you modify your `Cargo.toml`, Cargo attempts to minimize the changes +made to the `Cargo.lock`. The intuition of conservative updates is: **if the +change you made was unrelated to another dependency, it shouldn't change**. + +Let's say that after developing the library for a little while, we decide that +we want to add support for time zones. First, let's add in the `tz` dependency +to our package: + +``` + [package] + name = "datetime" + version = "0.1.0" + authors = ["Yehuda Katz "] + + [dependencies] + time = "0.1.35" ++ tz = "0.2.1" +``` + +After using the crate in our library, let's run `cargo build` again: + +``` +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading tz v0.2.1 + Downloading byteorder v0.5.1 + Compiling byteorder v0.5.1 + Compiling tz v0.2.1 + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) +``` + +Cargo downloaded `tz` (and its dependency `byteorder`) and compiled them, but it +**didn't** touch the packages we were already using (`kernel32-sys`, `libc`, +`time`, `winapi` and `winapi-build`). Even if one of those package authors +published an update in the meantime, you can be sure that adding new crates +won't mess with unrelated ones. + +Conservative updates attempt to significantly reduce unexpected changes to your +source code. It stands in stark contrast to 'rebuild the world', which allows a +small change to dependencies to rebuild the entire graph, wreaking havoc in its +wake. + +**As a rule, Cargo attempts to minimize the effects of intentional changes to + direct dependencies.** + +## Indirect Dependencies "Just Work" + +One of the most basic goals of an application package manager is separating +direct dependencies, which are required by the application, and indirect +dependencies, which those dependencies need in order to work. + +As we've seen in the `datetime` crate we built, we only needed to specify +dependencies on `time` and `tz`, and Cargo automatically created the entire +graph of dependencies needed to make that work. It also serialized that graph +for future predictability. + +Since Cargo manages your dependencies for you, it can also make sure that it +compiles all of your dependencies (whether you knew about them directly or not) +appropriately for the task at hand. + +### Testing, Benchmarking, Releasing, Oh My + +Historically, people have shied away from the kinds of granular dependencies +we've seen here because of the configuration needed for each new dependency. + +For example, when running tests or type-checking your code, you would like to +compile the code as fast as possible to keep the feedback loop fast. On the +other hand, when benchmarking or releasing your code, you are willing to spend +plenty of time waiting for the compiler to optimize your code if it produces a +fast binary. + +It's important to compile not only your own code or your direct dependencies, +but all indirect dependencies with the same configuration. + +Cargo manages that process for you automatically. Let's add a benchmark to our +code: + +``` +#[bench] +fn bench_date(b: &mut Bencher) { + b.iter(|| DateTime::now()); +} +``` +If we then run `cargo bench`: + +``` +$ cargo bench + Compiling winapi v0.2.6 + Compiling libc v0.2.10 + Compiling byteorder v0.5.1 + Compiling winapi-build v0.1.1 + Compiling kernel32-sys v0.2.2 + Compiling tz v0.2.1 + Compiling time v0.1.35 + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) + Running target/release/datetime-2602656fcee02e68 + +running 1 test +test bench_date ... bench: 486 ns/iter (+/- 56) +``` + +Notice that we're re-compiling all of our dependencies. This is because `cargo +bench` defaults to release mode, which uses maximum optimizations. `cargo build +--release` similarly builds in optimized mode by default. + +> As an aside, the default behavior of each command is configurable through +> [profiles](http://doc.crates.io/manifest.html#the-profile-sections) in the +> `Cargo.toml`. This allows you to configure things like the optimization level, +> whether to include debug symbols and more. Rather than forcing you to use a +> custom workflow if something doesn't precisely meet your needs, the profiles +> feature allows you to customize the existing workflows and stay within Cargo's +> flows. + +### Platforms and Architectures + +Similarly, applications are often built for different architectures, operating +systems, or even operating system version. They can be compiled for maximum +portability or to make maximum use of available platform features. + +Libraries can be compiled as static libraries or dynamic libraries. And even +static libraries might want to do some dynamic linking (for example, against the +system version of `openssl`). + +**By standardizing what it means to build and configure a package, Cargo can apply +all of these configuration choices to your direct dependencies *and* indirect +dependencies**. + +### Shared Dependencies + +So far, we've looked at packages and their dependencies. But what if two +packages that your application depends on share a third dependency? + +For example, let's say that I decide to add the `nix` crate to my `datetime` +library for Unix-specific functionality. + +``` + [package] + name = "datetime" + version = "0.1.0" + authors = ["Yehuda Katz "] + + [dependencies] + time = "0.1.35" + tz = "0.2.1" ++ nix = "0.5.0" +``` + +As before, when I run `cargo build`, Cargo *conservatively* adds `nix` and its dependencies: + +``` +$ cargo build + Updating registry `https://github.com/rust-lang/crates.io-index` + Downloading nix v0.5.0 + Downloading bitflags v0.4.0 + Compiling bitflags v0.4.0 + Compiling nix v0.5.0 + Compiling datetime v0.1.0 (file:///Users/ykatz/Code/datetime) +``` + +But if we look a little closer, we'll notice that `nix` has a dependency on +`bitflags` **and** `libc`. It now **shares** the dependency on `libc` with the +`date` package. + +If my `datetime` crate gets `libc` types from `time` and hands them off to +`nix`, they better be the same `libc` or my program won't compile (and we +wouldn't want it to!) + +Today, Cargo will automatically share dependencies between crates if they depend +on the same **major version** (or minor version before 1.0), since Rust uses +[semantic versioning](http://semver.org/). This means that if `nix` and `datetime` +both depend on some version of `libc 0.2.x`, they will get the same version. In +this case, they do, and the program compiles. + +While this policy works well (and in fact is the same policy that system package +managers use), it doesn't always do exactly what people expect, especially when +it comes to coordinating a major version bump across the ecosystem. (In many +cases, it would be preferable for Cargo to hard-error than assume that a +dependency on `0.2.x` is simply unrelated to another dependency on `0.3.x`.) + +This problem is especially pernicious when multiple major versions of the same +package expose global symbols (using `#[no_mangle]` for example, or by including +other statically linked C libraries). + +We have some thoughts on ways to improve Cargo to handle these cases better, +including the ability for a package to more explicitly express when a dependency +is used purely internally and is not shared through its public interface. Those +packages could be more readily duplicated if needed, while dependencies that are +used in a package's public interface must not be. + +You should expect to see more on this topic in the months ahead. + +## Workflow + +As we've seen, **Cargo is not just a dependency manager, but Rust's primary +workflow tool**. + +This allows Rust to have a rich ecosystem of interconnected dependencies, +eliminating the need for applications to manually manage large dependency +graphs. Applications can benefit from a vibrant ecosystem of small packages that +do one thing and do it well, and let Cargo handle the heavy lifting of keeping +everything up to date and compiling correctly. + +Even a small crate like the `datetime` example we built has a few dependencies +on small, targeted crates, and each of those crates has some dependencies of its +own. + +By defining shared, well-known workflows, like "build", "test", "bench", "run", +and "docs", Cargo provides Rust programmers with a way to think about what +they're trying to accomplish at a high level, and not have to worry about what +each of those workflows mean for indirect dependencies. + +This allows us to get closer to the holy grail of making those indirect +dependency graphs "invisible", empowering individuals to do more on their hobby +projects, small teams to do more on their products, and large teams to have a +high degree of confidence in the output of their work. + +We're all very proud of the way that comes together in +[Servo](https://github.com/servo/servo), the Rust-based web browser built using +Cargo. The code that they have written as a small team is impressive, but even +more impressive is how much of Servo is maintained and used by the wider Rust +community. + +Concretely, this means that Servo's encoding library (and many components like +it) is not a deeply nested part of Servo's main tree, but rather an +[external library](https://crates.io/crates/encoding) that anyone in the +ecosystem can use. This makes it possible for other Rust libraries, like web +frameworks, to easily use the same encoding library used by a web browser, +sharing the costs and benefits of maintenance. + +With a workflow tool that provides predictability, even in the face of many +indirect dependencies, we can all build higher together. From 804b300262ce182eda5452a69339e0acba28e923 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:01:48 -0700 Subject: [PATCH 221/386] Address nits --- _posts/2016-05-05-cargo-pillars.md | 67 +++++++++++++++++------------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 29a35dced..bdd4b32d1 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -10,24 +10,30 @@ the Rust programming language. That concern is driven by a desire to answer questions like: -1. If I want to use `libgit2` in my project, how easy is it? +1. How easy is it to use an external library, like `libgit2`, in my project? + 2. If I build my project on a different machine, for a different architecture, in CI or for release, am I building from the same source code? + 3. If I build my project for testing, will my indirect dependencies be compiled with debug symbols? If I build my project for release, will my indirect dependencies be compiled with maximum optimizations? How can I be sure? + 4. If someone published a new version of one of my dependencies after I commit, will my CI environment use the same source code? My production environment? + 5. If I add a new dependency (or upgrade one), can that break the build? Can it affect unrelated dependencies? Under what conditions? **All of these questions (and many more like them) have one thing in common: predictability**. One solution to this problem, common in the systems space, is -vendoring dependencies -- forking them directly into an application's repository --- and then managing them manually. But this comes at a substantial per-project -cost, since there's more to manage. It also comes at an ecosystem-wide cost, -since there's less sharing. Making sure you can answer all of the questions -above, all of the time, is hard work. +vendoring dependencies—forking them directly into an application's +repository—and then managing them manually. But this comes at a +substantial per-project cost, since there's more to manage. It also comes at an +ecosystem-wide cost, since the work involved cannot easily be shared between +libraries; it has to be redone instead for each application that brings a set of +libraries together. And making sure you can answer all of the questions above, all +of the time, is hard work. Package managers for higher-level languages have shown that by turning dependency management over to a shared tool, you can have predictability, easy @@ -53,11 +59,13 @@ We'll look at each of these pillars in turn. ## Predictability -Cargo's predictability goals start with a simple guarantee: **once a -project successfully compiles, subsequent compiles will use exactly the same -source code, across machines and environments**. +Cargo's predictability goals start with a simple guarantee: **once a project +successfully compiles on one machine, subsequent compiles across machines and +environments will use exactly the same source code**. -To achieve this guarantee, Cargo uses several strategies: +This guarantee is accomplished without incorporating the source code for +dependencies directly into a project repository. Instead, Cargo uses several +strategies: 1. The first time a build succeeds, Cargo emits a `Cargo.lock` file, which contains a manifest of precisely which source code was used in the @@ -84,6 +92,7 @@ First, we'll use `cargo new` to start us out: ``` $ cargo new datetime +$ cd datetime $ ls Cargo.toml src $ cat Cargo.toml @@ -98,7 +107,7 @@ authors = ["Yehuda Katz "] We don't want to build the date or time functionality from scratch, so let's edit the `Cargo.toml` and add the `time` crate from crates.io: -``` +```diff [package] name = "datetime" version = "0.1.0" @@ -145,15 +154,14 @@ $ cargo build --verbose Fresh datetime v0.1.0 (file:///Users/ykatz/Code/datetime) ``` -Cargo isn't bothering to recompile packages that it knows are "fresh". If you've -ever had to configure a `Makefile` before, this should be a breath of fresh air -(no pun intended). +Cargo isn't bothering to recompile packages that it knows are "fresh", like +`make`, but without having to write the `Makefile`. But how does Cargo know that everything is fresh? When Cargo builds a crate, it emits a file called `Cargo.lock` that contains the precise versions of all of its resolved dependencies: -``` +```toml [root] name = "datetime" version = "0.1.0" @@ -178,19 +186,13 @@ The `Cargo.lock` contains a serialized version of the entire **resolved** dependency graph, including precise versions of all of the source code included in the build. In the case of a package from crates.io, Cargo stores the name and version of the dependency. This is enough information to uniquely identify -source code from crates.io, because the registry is **append only** (no changes -to already-published packages are ever allowed). +source code from [crates.io](https://crates.io/), because the registry is +**append only** (no changes to already-published packages are allowed). In addition, the metadata for the registry is stored in a separate git repository, and includes checksum for the relevant package. Before Cargo ever unpacks a crate it downloads, it first validates the checksum. -Here's what the entry for `kernel32-sys 0.2.2` looks like: - -``` -{"name":"kernel32-sys","vers":"0.2.2","deps":[{"name":"winapi","req":"^0.2.5","features":[],"optional":false,"default_features":true,"target":null,"kind":"normal"},{"name":"winapi-build","req":"^0.1.1","features":[],"optional":false,"default_features":true,"target":null,"kind":"build"}],"cksum":"7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d","features":{},"yanked":false} -``` - ### Collaborating Now for the real test. Let's push our code up to GitHub and develop it on a @@ -255,7 +257,7 @@ Rust ecosystem**. All of this means that your application won't change if you don't make any changes to your dependencies, but what happens when you need to change them? -Cargo adds another layer of protection with **conservative updates**. This means +Cargo adds another layer of protection with *conservative updates*. This means that if you modify your `Cargo.toml`, Cargo attempts to minimize the changes made to the `Cargo.lock`. The intuition of conservative updates is: **if the change you made was unrelated to another dependency, it shouldn't change**. @@ -288,7 +290,7 @@ $ cargo build ``` Cargo downloaded `tz` (and its dependency `byteorder`) and compiled them, but it -**didn't** touch the packages we were already using (`kernel32-sys`, `libc`, +didn't touch the packages we were already using (`kernel32-sys`, `libc`, `time`, `winapi` and `winapi-build`). Even if one of those package authors published an update in the meantime, you can be sure that adding new crates won't mess with unrelated ones. @@ -316,7 +318,7 @@ Since Cargo manages your dependencies for you, it can also make sure that it compiles all of your dependencies (whether you knew about them directly or not) appropriately for the task at hand. -### Testing, Benchmarking, Releasing, Oh My +### Testing, Benchmarking, Docs, Oh My Historically, people have shied away from the kinds of granular dependencies we've seen here because of the configuration needed for each new dependency. @@ -369,6 +371,11 @@ bench` defaults to release mode, which uses maximum optimizations. `cargo build > feature allows you to customize the existing workflows and stay within Cargo's > flows. +Similarly, the `cargo doc` command will automatically compile not just your +code, but that of your dependencies as well. The upshot is that the API docs it +automatically produces include the crates you depend on, so if your APIs mention +types from those crates, your clients can follow those links. + ### Platforms and Architectures Similarly, applications are often built for different architectures, operating @@ -463,7 +470,7 @@ on small, targeted crates, and each of those crates has some dependencies of its own. By defining shared, well-known workflows, like "build", "test", "bench", "run", -and "docs", Cargo provides Rust programmers with a way to think about what +and "doc", Cargo provides Rust programmers with a way to think about what they're trying to accomplish at a high level, and not have to worry about what each of those workflows mean for indirect dependencies. @@ -482,8 +489,10 @@ Concretely, this means that Servo's encoding library (and many components like it) is not a deeply nested part of Servo's main tree, but rather an [external library](https://crates.io/crates/encoding) that anyone in the ecosystem can use. This makes it possible for other Rust libraries, like web -frameworks, to easily use the same encoding library used by a web browser, -sharing the costs and benefits of maintenance. +frameworks, to easily use a browser-grade encoding library, sharing the costs +and benefits of maintenance. And it flows both ways: recently, a fast +line-breaking library that showed up for a Rust-based text editor +[replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696). With a workflow tool that provides predictability, even in the face of many indirect dependencies, we can all build higher together. From c778211ad8c039bede98f3f423e5145e19aa3c0d Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:11:31 -0700 Subject: [PATCH 222/386] A few more edits --- _posts/2016-05-05-cargo-pillars.md | 39 +++++++++++++++--------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index bdd4b32d1..5d9bc5321 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -29,11 +29,11 @@ That concern is driven by a desire to answer questions like: predictability**. One solution to this problem, common in the systems space, is vendoring dependencies—forking them directly into an application's repository—and then managing them manually. But this comes at a -substantial per-project cost, since there's more to manage. It also comes at an -ecosystem-wide cost, since the work involved cannot easily be shared between -libraries; it has to be redone instead for each application that brings a set of -libraries together. And making sure you can answer all of the questions above, all -of the time, is hard work. +substantial per-project cost, since there's more to manage and configure. It +also comes at an ecosystem-wide cost, since the work involved cannot easily be +shared between libraries; it has to be redone instead for each application that +brings a set of libraries together. And making sure you can answer all of the +questions above, all of the time, is hard work indeed. Package managers for higher-level languages have shown that by turning dependency management over to a shared tool, you can have predictability, easy @@ -187,11 +187,12 @@ dependency graph, including precise versions of all of the source code included in the build. In the case of a package from crates.io, Cargo stores the name and version of the dependency. This is enough information to uniquely identify source code from [crates.io](https://crates.io/), because the registry is -**append only** (no changes to already-published packages are allowed). +*append only* (no changes to already-published packages are allowed). -In addition, the metadata for the registry is stored in a separate git -repository, and includes checksum for the relevant package. Before Cargo ever -unpacks a crate it downloads, it first validates the checksum. +In addition, the metadata for the registry is stored in a +[separate git repository](https://github.com/rust-lang/crates.io-index/), and +includes checksum for the relevant package. Before Cargo ever unpacks a crate it +downloads, it first validates the checksum. ### Collaborating @@ -217,7 +218,7 @@ versions of all dependencies as before**. And if we wanted to start collaboratin with other developers on GitHub (or with other members of our team at work), we would continue to get the same level of predictability. -### Common conventions: examples and tests +### Common conventions: examples, tests, and docs Now that we've written our snazzy new `datetime` crate, we'd love to write an example to show other developers how it should be used. We create a new file @@ -248,7 +249,12 @@ build your examples as well, which prevents them from getting out of sync with your code, and ensures they continue to compile as long as your tests are passing. -These are just two examples of a general approach: **Cargo defines a common set of +Similarly, the `cargo doc` command will automatically compile not just your +code, but that of your dependencies as well. The upshot is that the API docs it +automatically produces include the crates you depend on, so if your APIs mention +types from those crates, your clients can follow those links. + +These are just a few examples of a general point: **Cargo defines a common set of conventions and workflows that operate precisely the same way across the entire Rust ecosystem**. @@ -318,7 +324,7 @@ Since Cargo manages your dependencies for you, it can also make sure that it compiles all of your dependencies (whether you knew about them directly or not) appropriately for the task at hand. -### Testing, Benchmarking, Docs, Oh My +### Testing, Benchmarking, Releasing, Oh My Historically, people have shied away from the kinds of granular dependencies we've seen here because of the configuration needed for each new dependency. @@ -371,11 +377,6 @@ bench` defaults to release mode, which uses maximum optimizations. `cargo build > feature allows you to customize the existing workflows and stay within Cargo's > flows. -Similarly, the `cargo doc` command will automatically compile not just your -code, but that of your dependencies as well. The upshot is that the API docs it -automatically produces include the crates you depend on, so if your APIs mention -types from those crates, your clients can follow those links. - ### Platforms and Architectures Similarly, applications are often built for different architectures, operating @@ -423,7 +424,7 @@ $ cargo build ``` But if we look a little closer, we'll notice that `nix` has a dependency on -`bitflags` **and** `libc`. It now **shares** the dependency on `libc` with the +`bitflags` *and* `libc`. It now *shares* the dependency on `libc` with the `date` package. If my `datetime` crate gets `libc` types from `time` and hands them off to @@ -431,7 +432,7 @@ If my `datetime` crate gets `libc` types from `time` and hands them off to wouldn't want it to!) Today, Cargo will automatically share dependencies between crates if they depend -on the same **major version** (or minor version before 1.0), since Rust uses +on the same *major* version (or minor version before 1.0), since Rust uses [semantic versioning](http://semver.org/). This means that if `nix` and `datetime` both depend on some version of `libc 0.2.x`, they will get the same version. In this case, they do, and the program compiles. From eef51ecef2e5c4f30e241ca0214fe58966e0bb00 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:38:34 -0700 Subject: [PATCH 223/386] Rebuild intro --- _posts/2016-05-05-cargo-pillars.md | 64 ++++++++++++++++++++---------- 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 5d9bc5321..b936c44e9 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -8,19 +8,54 @@ description: "Cargo makes dependency management in Rust easy and predictable" Cargo's goal is to make modern application package management a core value of the Rust programming language. -That concern is driven by a desire to answer questions like: +In practice, this goal translates to being able to build a new browser engine +like [Servo](https://github.com/servo/servo) out of 250 community-driven +libraryes—and counting. Cargo's build system is a thin wrapper around +Cargo, and after a fresh checkout, you're only one command away from seeing the +whole dependency graph built: -1. How easy is it to use an external library, like `libgit2`, in my project? +``` +... + Compiling num-complex v0.1.32 + Compiling bitflags v0.6.0 + Compiling angle v0.1.0 (https://github.com/emilio/angle?branch=servo#eefe3506) + Compiling backtrace v0.2.1 + Compiling smallvec v0.1.5 + Compiling browserhtml v0.1.4 (https://github.com/browserhtml/browserhtml?branch=gh-pages#0ca50842) + Compiling unicase v1.4.0 + Compiling fnv v1.0.2 + Compiling heapsize_plugin v0.1.4 +.. +``` + +Why do these granular dependencies matter? + +Concretely, they mean that Servo's encoding library (and many components like +it) is not a deeply nested part of Servo's main tree, but rather an +[external library](https://crates.io/crates/encoding) that anyone in the +ecosystem can use. This makes it possible for other Rust libraries, like web +frameworks, to easily use a browser-grade encoding library, sharing the costs +and benefits of maintenance. And it flows both ways: recently, a fast +line-breaking library that showed up for a Rust-based text editor +[replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696). -2. If I build my project on a different machine, for a different architecture, +## The core concerns of dependency management + +To make this all work at the scale of an app like Servo, you need a dependency +management approach with good answers to a number of thorny questions: + +1. How easy is it to add a an external library, like a new linebreaker, to Servo? + +2. If I build Servo on a different machine, for a different architecture, in CI or for release, am I building from the same source code? -3. If I build my project for testing, will my indirect dependencies be compiled - with debug symbols? If I build my project for release, will my indirect +3. If I build Servo for testing, will its indirect dependencies be compiled + with debug symbols? If I build Servo for release, will its indirect dependencies be compiled with maximum optimizations? How can I be sure? -4. If someone published a new version of one of my dependencies after I commit, - will my CI environment use the same source code? My production environment? +4. If someone published a new version of one of Servo's dependencies after I + commit to Servo, will my CI environment use the same source code as my + machine? My production environment? 5. If I add a new dependency (or upgrade one), can that break the build? Can it affect unrelated dependencies? Under what conditions? @@ -480,20 +515,5 @@ dependency graphs "invisible", empowering individuals to do more on their hobby projects, small teams to do more on their products, and large teams to have a high degree of confidence in the output of their work. -We're all very proud of the way that comes together in -[Servo](https://github.com/servo/servo), the Rust-based web browser built using -Cargo. The code that they have written as a small team is impressive, but even -more impressive is how much of Servo is maintained and used by the wider Rust -community. - -Concretely, this means that Servo's encoding library (and many components like -it) is not a deeply nested part of Servo's main tree, but rather an -[external library](https://crates.io/crates/encoding) that anyone in the -ecosystem can use. This makes it possible for other Rust libraries, like web -frameworks, to easily use a browser-grade encoding library, sharing the costs -and benefits of maintenance. And it flows both ways: recently, a fast -line-breaking library that showed up for a Rust-based text editor -[replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696). - With a workflow tool that provides predictability, even in the face of many indirect dependencies, we can all build higher together. From 8891af6e31a44f708b197aa89a93b64679b7acfc Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:39:22 -0700 Subject: [PATCH 224/386] Typo fix --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index b936c44e9..477b2ca51 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -10,7 +10,7 @@ the Rust programming language. In practice, this goal translates to being able to build a new browser engine like [Servo](https://github.com/servo/servo) out of 250 community-driven -libraryes—and counting. Cargo's build system is a thin wrapper around +libraries—and counting. Cargo's build system is a thin wrapper around Cargo, and after a fresh checkout, you're only one command away from seeing the whole dependency graph built: From bb027aee8b3cecf7584fc5e49c336f91f05ad251 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:39:51 -0700 Subject: [PATCH 225/386] Typo fix --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 477b2ca51..7ec69acbe 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -10,7 +10,7 @@ the Rust programming language. In practice, this goal translates to being able to build a new browser engine like [Servo](https://github.com/servo/servo) out of 250 community-driven -libraries—and counting. Cargo's build system is a thin wrapper around +libraries—and counting. Servo's build system is a thin wrapper around Cargo, and after a fresh checkout, you're only one command away from seeing the whole dependency graph built: From 89850b762eb00f15bc2832e81cef62573eef25cb Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:43:57 -0700 Subject: [PATCH 226/386] Clarity --- _posts/2016-05-05-cargo-pillars.md | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 7ec69acbe..041770398 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -35,9 +35,12 @@ it) is not a deeply nested part of Servo's main tree, but rather an [external library](https://crates.io/crates/encoding) that anyone in the ecosystem can use. This makes it possible for other Rust libraries, like web frameworks, to easily use a browser-grade encoding library, sharing the costs -and benefits of maintenance. And it flows both ways: recently, a fast -line-breaking library that showed up for a Rust-based text editor -[replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696). +and benefits of maintenance. And it flows both ways: recently, a new +[Rust-based text editor](https://github.com/google/xi-editor) came on the scene, +and happened to provide a fast line-breaking library. Within days, that library +[replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696), +decreasing Servo's maintenance burden and increasing sharing in the Rust +ecosystem. ## The core concerns of dependency management From bfe0f2b32fcf952bb83e27e8c9e025300cf8f9b8 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:44:38 -0700 Subject: [PATCH 227/386] Clarity --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 041770398..28aa1e91c 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -36,7 +36,7 @@ it) is not a deeply nested part of Servo's main tree, but rather an ecosystem can use. This makes it possible for other Rust libraries, like web frameworks, to easily use a browser-grade encoding library, sharing the costs and benefits of maintenance. And it flows both ways: recently, a new -[Rust-based text editor](https://github.com/google/xi-editor) came on the scene, +[Rust-based text editor](https://github.com/google/xi-editor) was announced, and happened to provide a fast line-breaking library. Within days, that library [replaced Servo's old custom linebreaker](https://twitter.com/mbrubeck/status/726791246014877696), decreasing Servo's maintenance burden and increasing sharing in the Rust From 42ff46de8052c2bd46d2e21a0491fc4b6f352632 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:47:07 -0700 Subject: [PATCH 228/386] More precision about crate count --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 28aa1e91c..e0bde4151 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -9,7 +9,7 @@ Cargo's goal is to make modern application package management a core value of the Rust programming language. In practice, this goal translates to being able to build a new browser engine -like [Servo](https://github.com/servo/servo) out of 250 community-driven +like [Servo](https://github.com/servo/servo) out of 247 community-driven libraries—and counting. Servo's build system is a thin wrapper around Cargo, and after a fresh checkout, you're only one command away from seeing the whole dependency graph built: From b57949a1b64ec649367284a4fb743bd3473013a2 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:47:36 -0700 Subject: [PATCH 229/386] Fix up compilation snippet --- _posts/2016-05-05-cargo-pillars.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index e0bde4151..b8e44e45a 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -15,7 +15,6 @@ Cargo, and after a fresh checkout, you're only one command away from seeing the whole dependency graph built: ``` -... Compiling num-complex v0.1.32 Compiling bitflags v0.6.0 Compiling angle v0.1.0 (https://github.com/emilio/angle?branch=servo#eefe3506) @@ -25,7 +24,7 @@ whole dependency graph built: Compiling unicase v1.4.0 Compiling fnv v1.0.2 Compiling heapsize_plugin v0.1.4 -.. + ... ``` Why do these granular dependencies matter? From e6003b4e4b733e74a9d6e7b3e8f43d1b7feec76a Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Thu, 5 May 2016 09:51:34 -0700 Subject: [PATCH 230/386] Minor fixes --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index b8e44e45a..5661cca1d 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -142,7 +142,7 @@ authors = ["Yehuda Katz "] ``` We don't want to build the date or time functionality from scratch, so let's -edit the `Cargo.toml` and add the `time` crate from crates.io: +edit the `Cargo.toml` and add the `time` crate from [crates.io](https://crates.io/): ```diff [package] From b5213623669849c85d164c9b1b8d7a7703b65b15 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 5 May 2016 09:58:29 -0700 Subject: [PATCH 231/386] Small typo --- _posts/2016-05-05-cargo-pillars.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index 5661cca1d..a4ccd2e64 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -46,7 +46,7 @@ ecosystem. To make this all work at the scale of an app like Servo, you need a dependency management approach with good answers to a number of thorny questions: -1. How easy is it to add a an external library, like a new linebreaker, to Servo? +1. How easy is it to add an external library, like a new linebreaker, to Servo? 2. If I build Servo on a different machine, for a different architecture, in CI or for release, am I building from the same source code? From af322c8e42d255bdc4ddd2c25c7cb130692b8323 Mon Sep 17 00:00:00 2001 From: Simon Sapin Date: Thu, 5 May 2016 19:34:19 +0200 Subject: [PATCH 232/386] =?UTF-8?q?rust-encoding=20is=20not=20"Servo?= =?UTF-8?q?=E2=80=99s"?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The phrasing suggested that Servo "owns" the rust-encoding library. This is not the case: it is primarily developed by Kang Seonghoon who is a member of the Rust community but not directly affiliated to Servo. To avoid sounding like Servo is stealing credit from Kang, this changes the example to rust-url which I developed while employed by Mozilla to work on Servo, and is also used in a number of projects outside of Servo. --- _posts/2016-05-05-cargo-pillars.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_posts/2016-05-05-cargo-pillars.md b/_posts/2016-05-05-cargo-pillars.md index a4ccd2e64..b1be1ed53 100644 --- a/_posts/2016-05-05-cargo-pillars.md +++ b/_posts/2016-05-05-cargo-pillars.md @@ -29,11 +29,11 @@ whole dependency graph built: Why do these granular dependencies matter? -Concretely, they mean that Servo's encoding library (and many components like +Concretely, they mean that Servo's URL library (and many components like it) is not a deeply nested part of Servo's main tree, but rather an -[external library](https://crates.io/crates/encoding) that anyone in the +[external library](https://crates.io/crates/url) that anyone in the ecosystem can use. This makes it possible for other Rust libraries, like web -frameworks, to easily use a browser-grade encoding library, sharing the costs +frameworks, to easily use a browser-grade URL library, sharing the costs and benefits of maintenance. And it flows both ways: recently, a new [Rust-based text editor](https://github.com/google/xi-editor) was announced, and happened to provide a fast line-breaking library. Within days, that library From 21e1c5101dd0cd430c8e30a29f9f587b922c4bdf Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 9 May 2016 08:20:54 -0700 Subject: [PATCH 233/386] 2016 survey post --- _posts/2016-05-09-survey.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 _posts/2016-05-09-survey.md diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md new file mode 100644 index 000000000..bd6030a58 --- /dev/null +++ b/_posts/2016-05-09-survey.md @@ -0,0 +1,31 @@ +--- +layout: post +title: "Launching the 2016 State of the Rust Language Survey" +author: The Rust Community Team +description: "Hearing from you about the first year of Rust" +--- + +Rust's first birthday is upon us (on May 15th, 2016), and we want to take this +opportunity to reflect on where we've been, and where we're going. The Rust core +team plans a post next week giving some of their perspective on the year. But we +are also eager to hear from you. + +Thus, as part of the celebrations, the community team is pleased to announce the +official +[2016 State of the Rust Language Survey](http://goo.gl/forms/HaesyIg73g)! +Whether or not you use Rust today, we want to to know your opinions. Your +responses will help the project understand its strengths and weaknesses, and to +establish development priorities for the future. + +Completing this survey should take about 5 to 10 minutes, and is anonymous +unless you choose to give us your contact information. We will be accepting +submissions until June 8th, 2016. + +Please help us spread the word by sharing the above link on your social network +feeds, at meetups, and around your office and other communities. + +Once the survey closes, we will summarize and visualize the results here on +http://blog.rust-lang.org/. If you have any questions, please feel free to email +the Rust Community team at community-team [at] rust-lang [dot] org. + +Happy birthday, Rust. Have another great year. From 819757a8f1b282ba32d48ff797812baa4d7c2ee0 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 9 May 2016 08:27:12 -0700 Subject: [PATCH 234/386] Fix survey title --- _posts/2016-05-09-survey.md | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md index bd6030a58..e4bc5a9c1 100644 --- a/_posts/2016-05-09-survey.md +++ b/_posts/2016-05-09-survey.md @@ -1,6 +1,6 @@ --- layout: post -title: "Launching the 2016 State of the Rust Language Survey" +title: "Launching the 2016 State of Rust Survey" author: The Rust Community Team description: "Hearing from you about the first year of Rust" --- @@ -11,11 +11,10 @@ team plans a post next week giving some of their perspective on the year. But we are also eager to hear from you. Thus, as part of the celebrations, the community team is pleased to announce the -official -[2016 State of the Rust Language Survey](http://goo.gl/forms/HaesyIg73g)! -Whether or not you use Rust today, we want to to know your opinions. Your -responses will help the project understand its strengths and weaknesses, and to -establish development priorities for the future. +official [2016 State of Rust Survey](http://goo.gl/forms/HaesyIg73g)! Whether +or not you use Rust today, we want to to know your opinions. Your responses will +help the project understand its strengths and weaknesses, and to establish +development priorities for the future. Completing this survey should take about 5 to 10 minutes, and is anonymous unless you choose to give us your contact information. We will be accepting From 14007046d4a5b9917eceef2aa5650b464d81846b Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 9 May 2016 08:55:02 -0700 Subject: [PATCH 235/386] Add thanks, mailto --- _posts/2016-05-09-survey.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md index e4bc5a9c1..5907936ac 100644 --- a/_posts/2016-05-09-survey.md +++ b/_posts/2016-05-09-survey.md @@ -18,13 +18,15 @@ development priorities for the future. Completing this survey should take about 5 to 10 minutes, and is anonymous unless you choose to give us your contact information. We will be accepting -submissions until June 8th, 2016. +submissions until June 8th, 2016. If you have any questions, please feel free to +email the Rust Community team at +[community-team@rust-lang.org](mailto:community-team@rust-lang.org). Please help us spread the word by sharing the above link on your social network feeds, at meetups, and around your office and other communities. -Once the survey closes, we will summarize and visualize the results here on -http://blog.rust-lang.org/. If you have any questions, please feel free to email -the Rust Community team at community-team [at] rust-lang [dot] org. +Thanks, everyone who helped develop, polish, and test the survey! Once it +closes, we will summarize and visualize the results here on +http://blog.rust-lang.org/. Happy birthday, Rust. Have another great year. From eb45f1352fd92a387d842dcb4668384f61a3ce65 Mon Sep 17 00:00:00 2001 From: Aaron Turon Date: Mon, 9 May 2016 09:06:11 -0700 Subject: [PATCH 236/386] Minor wording tweak --- _posts/2016-05-09-survey.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md index 5907936ac..0dd5cb046 100644 --- a/_posts/2016-05-09-survey.md +++ b/_posts/2016-05-09-survey.md @@ -23,7 +23,7 @@ email the Rust Community team at [community-team@rust-lang.org](mailto:community-team@rust-lang.org). Please help us spread the word by sharing the above link on your social network -feeds, at meetups, and around your office and other communities. +feeds, at meetups, around your office and in other communities. Thanks, everyone who helped develop, polish, and test the survey! Once it closes, we will summarize and visualize the results here on From 3141782190422092ee3d83c545f4a4a98a7c9499 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Mon, 9 May 2016 09:22:45 -0700 Subject: [PATCH 237/386] Linkify the blog --- _posts/2016-05-09-survey.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md index 0dd5cb046..5391d6aaa 100644 --- a/_posts/2016-05-09-survey.md +++ b/_posts/2016-05-09-survey.md @@ -27,6 +27,6 @@ feeds, at meetups, around your office and in other communities. Thanks, everyone who helped develop, polish, and test the survey! Once it closes, we will summarize and visualize the results here on -http://blog.rust-lang.org/. +[http://blog.rust-lang.org/](http://blog.rust-lang.org). Happy birthday, Rust. Have another great year. From 3cd253b1e280f59a3ebcaf9fe3cb0c785305ad6d Mon Sep 17 00:00:00 2001 From: "Daniel Campoverde [alx741]" Date: Mon, 9 May 2016 15:03:37 -0500 Subject: [PATCH 238/386] Typo fix --- _posts/2016-05-09-survey.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-09-survey.md b/_posts/2016-05-09-survey.md index 5391d6aaa..9a8d9fa27 100644 --- a/_posts/2016-05-09-survey.md +++ b/_posts/2016-05-09-survey.md @@ -12,7 +12,7 @@ are also eager to hear from you. Thus, as part of the celebrations, the community team is pleased to announce the official [2016 State of Rust Survey](http://goo.gl/forms/HaesyIg73g)! Whether -or not you use Rust today, we want to to know your opinions. Your responses will +or not you use Rust today, we want to know your opinions. Your responses will help the project understand its strengths and weaknesses, and to establish development priorities for the future. From 858fdc4af7f2012f404bf4576f17c9ef78a15a23 Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Sun, 1 May 2016 02:05:46 +0000 Subject: [PATCH 239/386] Add a blog post about rustup --- _posts/2016-05-13-rustup.md | 553 ++++++++++++++++++++++++++++++++++++ 1 file changed, 553 insertions(+) create mode 100644 _posts/2016-05-13-rustup.md diff --git a/_posts/2016-05-13-rustup.md b/_posts/2016-05-13-rustup.md new file mode 100644 index 000000000..dae4af730 --- /dev/null +++ b/_posts/2016-05-13-rustup.md @@ -0,0 +1,553 @@ +--- +layout: post +title: "Taking Rust everywhere with rustup" +author: Brian Anderson +description: "The rustup toolchain manager makes cross-compilation in Rust a breeze" +--- + +*Cross-compilation* is an imposing term for a common kind of desire: + +* You want to build an app for Android, or iOS, or your router using your laptop. + +* You want to write, test and build code on your Mac, but deploy it to your Linux server. + +* You want your Linux-based build servers to produce binaries for all the platforms + you ship on. + +* You want to build an ultraportable binary you can ship to any Linux platform. + +* You want to target the browser with [Emscripten] or [WebAssembly]. + +[Emscripten]: http://kripken.github.io/emscripten-site/ +[WebAssembly]: https://webassembly.github.io/ + +In other words, **you want to develop/build on one "host" platform, but get a +final binary that runs on a different "target" platform**. + +Thanks to the [LLVM] backend, it's always been possible *in principle* +to cross-compile Rust code: just tell the backend to use a different +target! And indeed, intrepid hackers have put Rust on embedded systems +[like the Raspberry Pi 3], [bare metal ARM], [MIPS routers running +OpenWRT][OpenWRT], and many others. + +[LLVM]: http://llvm.org +[like the Raspberry Pi 3]: http://mirrors.link/posts/cross-compiling-rust-on-os-x-for-raspberry-pi-3 +[bare metal ARM]: https://blog.thiago.me/raspberry-pi-bare-metal-programming-with-rust/ +[OpenWRT]: https://github.com/japaric/rust-on-openwrt + +But in practice, there are a lot of ducks you have to get in a row to +make it work: the appropriate Rust standard library, a cross-compiling +C toolchain including linker, headers and binaries for C libraries, +and so on. This typically involves pouring over various blog posts +and package installers to get everything "just so". And the exact set +of tools can be different for every pair of host and target platforms. + +**The Rust community has been hard at work toward the goal of "push-button +cross-compilation"**. We want to provide a complete setup for a given +host/target pair with the run of a single command. Today we're happy to announce +that a major portion of this work is reaching beta status: we're building +binaries of the Rust standard library for a wide range of targets, and shipping +them to you via a new tool called **[rustup]**. + +[rustup]: https://www.rustup.rs + +## Introducing rustup + +At its heart, **rustup is a *toolchain manager* for Rust**. It can +download and switch between copies of the Rust compiler and standard +library for all supported platforms, and track Rust's nightly, beta, +and release [channels], as well as specific versions. In this way +rustup is similar to the [rvm], [rbenv] and [pyenv] tools for Ruby and +Python. I'll walk through all of this functionality, and the +situations where it's useful, in the rest of the post. + +[rvm]: https://rvm.io/ +[rbenv]: https://github.com/rbenv/rbenv +[pyenv]: https://github.com/yyuu/pyenv + +Today rustup is a command line application, and I'm going to show you some +examples of what it can do, but it's also a [Rust library], and eventually these +features are expected to be presented through a graphical interface where +appropriate — particularly on Windows. Getting cross-compilation set up should +eventually be a matter of checking a box in the Rust installer. + +Our ambitions go beyond managing just the Rust toolchain: to have a +true push-button experience for cross-compilation, it needs to set up +the C toolchain as well. That functionality is not shipping today, but +it's something we hope to incorporate over the next few months. + +[channels]: http://blog.rust-lang.org/2014/10/30/Stability.html +[Rust library]: https://github.com/rust-lang-nursery/rustup.rs/ + +## Basic toolchain management + +Let's start with something simple: installing multiple Rust toolchains. In this +example I create a new library, 'hello', then test it using rustc 1.8, then use +rustup to install and test that same crate on the 1.9 beta. + +
+ +
+ + + +That's an easy way to verify your code works on the next Rust release. That's +good Rust citizenship! + +We can use `rustup show` to show us the installed toolchains, and `rustup +update` to keep the up to date with Rust's releases. + +
+ +
+ +Finally, rustup can also change the default toolchain with `rustup default`: + +``` +$ rustc --version +rustc 1.8.0 (db2939409 2016-04-11) +$ rustup default 1.7.0 +info: syncing channel updates for '1.7.0-x86_64-unknown-linux-gnu' +info: downloading component 'rust' +info: installing component 'rust' +info: default toolchain set to '1.7.0-x86_64-unknown-linux-gnu' + + 1.7.0-x86_64-unknown-linux-gnu installed - rustc 1.7.0 (a5d1e7a59 2016-02-29) + +$ rustc --version +rustc 1.7.0 (a5d1e7a59 2016-02-29) +``` + +On Windows, [where Rust supports both the GNU and MSVC ABI][abi], you +might want to switch from the default stable toolchain on Windows, +which targets the 32-bit x86 architecture and the GNU ABI, to a +stable toolchain that targets the 64-bit, MSVC ABI. + +[abi]: https://www.rust-lang.org/downloads.html#win-foot + +``` +$ rustup default stable-x86_64-pc-windows-msvc +info: syncing channel updates for 'stable-x86_64-pc-windows-msvc' +info: downloading component 'rustc' +info: downloading component 'rust-std' +... + + stable-x86_64-pc-windows-msvc installed - rustc 1.8.0-stable (db2939409 2016-04-11) + +``` + +Here the "stable" toolchain name is appended with an extra identifier indicating +the compiler's architecture, in this case `x86_64-pc-windows-msvc`. This +identifier is called a "target triple": "target" because it specifies a platform +for which the compiler generates (targets) machine code; and "triple" for +historical reasons (in many cases "triples" are actually quads these +days). Target triples are the basic way we refer to particular common platforms; +`rustc` by default knows about 56 of them, and `rustup` today can obtain +compilers for 14, and standard libraries for 30. + +## Example: Building static binaries on Linux + +Now that we've got the basic pieces in place, let's apply them to +simple cross-compilation task: building an ultraportable static binary +for Linux. + +One of the unique features of Linux that has become increasingly appreciated is +its stable syscall interface. Because the Linux kernel puts exceptional effort +into maintaining a backward-compatible kernel interface, it's possible to +distribute [ELF] binaries with no dynamic library dependencies that will run on +any version of Linux. Besides being one of the features that make Docker +possible, it also allows developers to build self-contained applications and +deploy them to any machine running Linux, regardless of whether it's Ubuntu or +Fedora or any other distribution, and regardless of exact mix of software +libraries they have installed. + +[ELF]: https://en.wikipedia.org/wiki/Executable_and_Linkable_Format + +Today's Rust depends on libc, and on most Linuxes that means +glibc. For technical reasons, glibc cannot be fully statically linked, +making it unusable for producing a truly standalone +binary. Fortunately, an alternative exists: [musl], a small, modern +implementation of libc that *can* be statically linked. Rust has been +compatible with musl since version 1.1, but until recently developers +have needed to build their own compiler to benefit from it. + +[musl]: http://www.musl-libc.org/ + +With that background, let's walk through compiling a statically-linked Linux +executable. For this example you'll want to be running Linux — that is, your +*host platform* will be Linux, and your *target platform* will also be Linux, +just a different flavor: musl. (Yes, this is technically cross-compilation +even though both targets are Linux). + +I'm going to be running on Ubuntu 16.04 (using [this Docker +image]). We'll be building the basic hello world: + +[this Docker image]: https://hub.docker.com/r/brson/rustup-demo/ + +``` +rust:~$ cargo new --bin hello && cd hello +rust:~/hello$ cargo run + Compiling hello v0.1.0 (file:///home/rust/hello) + Running `target/debug/hello` +Hello, world! +``` + +That's with the default `x86_64-unknown-linux-gnu` target. And you can +see it has many dynamic dependencies: + +``` +rust:~/hello$ ldd target/debug/hello + linux-vdso.so.1 => (0x00007ffe5e979000) + libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fca26d03000) + libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fca26ae6000) + libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fca268cf000) + libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fca26506000) + /lib64/ld-linux-x86-64.so.2 (0x000056104c935000) + libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fca261fd000) +``` + +To compile for musl instead call `cargo` with the argument +`--target=x86_64-unknown-linux-musl`. If we just go ahead and try that +we'll get an error: + +``` +rust:~/hello$ cargo run --target=x86_64-unknown-linux-musl + Compiling hello v0.1.0 (file:///home/rust/hello) +error: can't find crate for `std` [E0463] +error: aborting due to previous error +Could not compile `hello`. +... + +``` + +The error tells us that the compiler can't find `std`. That is of +course because we haven't installed it. + +To start cross-compiling, you need to acquire a standard library for the target +platform. Previously, this was an error-prone, manual process — queue those +blog posts I mentioned earlier. But with rustup, it's just part of the usual +workflow: + +``` +rust:~/hello$ rustup target add x86_64-unknown-linux-musl +info: downloading component 'rust-std' for 'x86_64-unknown-linux-musl' +info: installing component 'rust-std' for 'x86_64-unknown-linux-musl' +rust:~/hello$ rustup show +installed targets for active toolchain +-------------------------------------- + +x86_64-unknown-linux-gnu +x86_64-unknown-linux-musl + +active toolchain +---------------- + +stable-x86_64-unknown-linux-gnu (default) +rustc 1.8.0 (db2939409 2016-04-11) +``` + +So I'm running the 1.8 toolchain for Linux on 64-bit x86, as indicated by the +`x86_64-unknown-linux-gnu` target triple, and now I can also target +`x86_64-unknown-linux-musl`. Neat. Surely we are ready to build a slick +statically-linked binary we can release into the cloud. Let's try: + +``` +rust:~/hello$ cargo run --target=x86_64-unknown-linux-musl + Compiling hello v0.1.0 (file:///hello) + Running `target/x86_64-unknown-linux-musl/debug/hello` +Hello, world! +``` + +And that... just worked! Run `ldd` on it for proof that it's the real +deal: + +``` +rust:~/hello$ ldd target/x86_64-unknown-linux-musl/debug/hello + not a dynamic executable +``` + +Now take that `hello` binary and copy it to any x86_64 machine running Linux and +it'll run just fine. + +For more advanced use of musl consider [rust-musl-builder], a Docker +image set up for musl development, which helpfully includes common C +libraries compiled for musl. + +[rust-musl-builder]: https://github.com/emk/rust-musl-builder + +## Example: Running Rust on Android + +One more example. This time building for Android, from Linux, i.e., +`arm-linux-androideabi` from `x86_64-unknown-linux-gnu`. This can also be done +from OS X or Windows, though on Windows the process is [less smooth right now][lsrt]. + +[lsrt]: https://gist.github.com/brson/a2b97ba8b3fbb7939143f584b6366751 + +To build for Android we need to the Android target, so let's +set up another 'hello, world' project and install it. + +``` +rust:~$ cargo new --bin hello && cd hello +rust:~/hello$ rustup target add arm-linux-androideabi +info: downloading component 'rust-std' for 'arm-linux-androideabi' +info: installing component 'rust-std' for 'arm-linux-androideabi' +rust:~/hello$ rustup show +installed targets for active toolchain +-------------------------------------- + +arm-linux-androideabi +x86_64-unknown-linux-gnu + +active toolchain +---------------- + +stable-x86_64-unknown-linux-gnu (default) +rustc 1.8.0 (db2939409 2016-04-11) +``` + +So let's see what happens if we try to just build our 'hello' +project without installing anything further: + +``` +rust:~/hello$ cargo build --target=arm-linux-androideabi + Compiling hello v0.1.0 (file:///home/rust/hello) +error: linking with `cc` failed: exit code: 1 +... (lots of noise elided) +error: aborting due to previous error +Could not compile `hello`. +``` + +The problem is that we don't have a linker that supports Android yet, +so let's take a moment's digression to talk about building for +Android. To develop for Android we need the [Andoid NDK]. It contains +the linker `rustc` needs to create Android binaries. To just *build* +Rust code that targets Android the only thing we need is the NDK, but +for practical development we'll want the [Android SDK] too. + +[Android NDK]: https://developer.android.com/ndk/guides/setup.html#install +[Android SDK]: https://developer.android.com/sdk/index.html + +On Linux, download and unpack them with the following commands (the +output of which is not included here): + +``` +rust:~/home$ cd +rust:~$ curl -O https://dl.google.com/android/android-sdk_r24.4.1-linux.tgz +rust:~$ tar xzf android-sdk_r24.4.1-linux.tgz +rust:~$ curl -O http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip +rust:~$ unzip android-ndk-r10e-linux-x86_64.zip +``` + +We further need to create what the NDK calls a ["standalone +toolchain"]. We're going to put ours in a directory called +`android-ndk-r10e`: + +["standalone toolchain"]: https://developer.android.com/ndk/guides/standalone_toolchain.html + +``` +rust:~$ android-ndk-r10e/build/tools/make-standalone-toolchain.sh \ + --platform=android-18 --toolchain=arm-linux-androideabi-clang3.6 \ + --install-dir=android-18-toolchain --ndk-dir=android-ndk-r10e/ --arch=arm +Auto-config: --toolchain=arm-linux-androideabi-4.8, --llvm-version=3.6 +Copying prebuilt binaries... +Copying sysroot headers and libraries... +Copying c++ runtime headers and libraries... +Copying files to: android-18-toolchain +Cleaning up... +Done. +``` + +Let's notice a few things about these commands. First, the NDK we +downloaded, `android-ndk-r10e-linux-x86_64.zip` is not the most recent +release (which at the time of this writing is 'r11c'). Rust's `std` is +built against `r10e` and links to symbols that are no longer included +in the NDK. So for now we have to use the older NDK. Second, in +building the standalone toolchain we passed "--platform=android-18" to +`make-standalone-toolchain.sh`. The "18" here is the Android [API +level](http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels). +Today, Rust's `arm-linux-androideabi` target is built against Android +API level 18, and should theoretically be forwards-compatible with +subsequent Android API levels. So we're picking level 18 to get the +greatest Android compatibility that Rust presently allows. + +The final thing for us to do is tell Cargo where to find the android +linker, which is in the standalone NDK toolchain we just created. To +do that we configure the `arm-linux-androideabi` target in +[`.cargo/config`] with the 'linker' value. And while we're doing that +we'll go ahead and set the default target for this project to Android +so we don't have to keep calling cargo with the `--target` option. + +[`.cargo/config`]: http://doc.crates.io/config.html + +```toml +[build] +target = "arm-linux-androideabi" + +[target.arm-linux-androideabi] +linker = "/home/rust/android-18-toolchain" +``` + +Now let's change back to the 'hello' project directory and try +to build again: + +``` +rust:~$ cd hello +rust:~/hello$ cargo build + Compiling hello v0.1.0 (file:///home/rust/hello) +``` + +Success! Of course just getting something to build is not the end of +the story. You've also got to package your code up as an Android +APK. For that you can use [cargo-apk]. I'm not going to show you that +now because I haven't yet worked through those steps myself. + +[cargo-apk]: https://users.rust-lang.org/t/announcing-cargo-apk/5501 + + + + + + + + + + +## Rust everywhere else + +Rust is a software platform with the potential to run on anything with +a CPU. In this post I showed you a little bit of what Rust can already +do, with the rustup tool. Today Rust runs on most of the platforms you +use daily. Tomorrow it will run everywhere. + +So what should you expect next? + +In the coming months we're going to continue removing barriers to Rust +cross-compilation. Today rustup provides access to the standard library, but as +we've seen in this post, there's more to cross-compilation than rustc + +std. It's acquiring and configuring the linker and C toolchain that is the most +vexing — each combination of host and target platform requires something +slightly different. We want to make this easier, and will be adding "NDK +support" to rustup. What this means will again depend on the exact scenario, but +we're going to start working from the most demanded uses cases, like Android, +and try to automate as much of the detection, installation and configuration of +the non-Rust toolchain components as we can. On Android for instance, the hope +is to automate everything for a basic initial setup except for accepting the +licenses. + +In addition to that there are multiple efforts to improve Rust +cross-compilation tooling, including [xargo], which can be used to +build the standard library for targets unsupported by rustup, and +[cargo-apk], which builds Android packages from Cargo packages. + +[cargo-apk]: https://users.rust-lang.org/t/announcing-cargo-apk/5501 +[xargo]: https://github.com/japaric/xargo + +Finally, the most exciting platform on the horizon for Rust is not a traditional +target for systems languages: the web. With [Emscripten] today it's quite easy +to run *C++* code on the web by converting LLVM IR to JavaScript (or the asm.js +subset of JavaScript). And the upcoming [WebAssembly][] (wasm) standard will +cement the web platform as a first-class target for programming languages. + +*Rust is uniquely-positioned to be the most powerful and usable wasm-targetting +language for the immediate future.* The same properties that make Rust so +portable to real hardware makes it nearly trivial to port Rust to wasm. The same +can't be said for languages with complex runtimes that include garbage +collectors. + +Rust has [already been ported to Emscripten][em] (at least twice), but the code +has not yet fully landed. This summer it's happening though: Rust + +Emscripten. Rust on the Web. Rust everywhere. + +[em]: https://internals.rust-lang.org/t/need-help-with-emscripten-port/3154 + +## Epilogue + +While many people are reporting success with rustup, it remains in beta, with +some [key outstanding bugs], and is not yet the officially recommended +installation method for Rust (though you should try it). We're going to keep +soliciting feedback, applying polish, and fixing bugs. Then we're going to +improve the rustup installation experience on Windows by +[embedding it into a GUI that behaves like a proper Windows installer][gui]. + +At that point we'll likely update the [download instructions on +www.rust-lang.org][dl] to recommend rustup. I expect all the existing +installation methods to remain available, including the non-rustup +Windows installers, but at that point our focus will be on improving +the installation experience through rustup. It's also plausible that +rustup itself will be packaged for package managers like Homebrew and +apt. + +If you want to try rustup for yourself, visit [www.rustup.rs] and follow the +instructions. Then leave feedback on the [dedicated forum thread][irlo], or +[file bugs] on the issue tracker. More information about rustup is available +in the [README]. + +[dl]: https://www.rust-lang.org/downloads.html +[irlo]: https://internals.rust-lang.org/t/beta-testing-rustup-rs/3316/112 +[gui]: https://github.com/rust-lang-nursery/rustup.rs/issues/253 +[key outstanding bugs]: https://github.com/rust-lang-nursery/rustup.rs/issues?q=is%3Aopen+is%3Aissue+label%3A%22initial+release%22 +[file bugs]: https://github.com/rust-lang-nursery/rustup.rs/issues +[www.rustup.rs]: https://www.rustup.rs +[emscripten]: https://kripken.github.io/emscripten-site/ +[README]: https://github.com/rust-lang-nursery/rustup.rs/blob/master/README.md + +## Thanks + +Rust would not be the powerful system it is without the help of many +individuals. Thanks to Diggory Blake for creating rustup, to Jorge +Aparicio for fixing lots of cross-compilation bugs and documenting the +process, Tomaka for pioneering Rust on Android, and Alex Crichton for +creating the release infrastructure for Rust's many platforms. + +And thanks to all the rustup contributors: Alex Crichton, Brian +Anderson, Corey Farwell, David Salter, Diggory Blake, Jacob Shaffer, +Jeremiah Peschka, Joe Wilm, Jorge Aparicio, Kai Noda, Kamal Marhubi, +Kevin K, llogiq, Mika Attila, NODA, Kai, Paul Padier, Severen Redwood, +Taylor Cramer, Tim Neumann, trolleyman, Vadim Petrochenkov, V Jackson, +Vladimir, Wayne Warren, Yasushi Abe, Y. T. Chung From d1b3e0bfa45065aaa0fd9d024a06bf65f9239c5b Mon Sep 17 00:00:00 2001 From: Brian Anderson Date: Fri, 13 May 2016 17:10:00 +0000 Subject: [PATCH 240/386] wip --- _posts/2016-05-13-rustup.md | 47 ++++--------------------------------- 1 file changed, 4 insertions(+), 43 deletions(-) diff --git a/_posts/2016-05-13-rustup.md b/_posts/2016-05-13-rustup.md index dae4af730..ecfcc5053 100644 --- a/_posts/2016-05-13-rustup.md +++ b/_posts/2016-05-13-rustup.md @@ -298,9 +298,7 @@ libraries compiled for musl. One more example. This time building for Android, from Linux, i.e., `arm-linux-androideabi` from `x86_64-unknown-linux-gnu`. This can also be done -from OS X or Windows, though on Windows the process is [less smooth right now][lsrt]. - -[lsrt]: https://gist.github.com/brson/a2b97ba8b3fbb7939143f584b6366751 +from OS X or Windows, though on Windows the setup is slightly different. To build for Android we need to the Android target, so let's set up another 'hello, world' project and install it. @@ -338,7 +336,7 @@ Could not compile `hello`. The problem is that we don't have a linker that supports Android yet, so let's take a moment's digression to talk about building for -Android. To develop for Android we need the [Andoid NDK]. It contains +Android. To develop for Android we need the [Android NDK]. It contains the linker `rustc` needs to create Android binaries. To just *build* Rust code that targets Android the only thing we need is the NDK, but for practical development we'll want the [Android SDK] too. @@ -381,7 +379,7 @@ downloaded, `android-ndk-r10e-linux-x86_64.zip` is not the most recent release (which at the time of this writing is 'r11c'). Rust's `std` is built against `r10e` and links to symbols that are no longer included in the NDK. So for now we have to use the older NDK. Second, in -building the standalone toolchain we passed "--platform=android-18" to +building the standalone toolchain we passed `--platform=android-18` to `make-standalone-toolchain.sh`. The "18" here is the Android [API level](http://developer.android.com/guide/topics/manifest/uses-sdk-element.html#ApiLevels). Today, Rust's `arm-linux-androideabi` target is built against Android @@ -417,47 +415,10 @@ rust:~/hello$ cargo build Success! Of course just getting something to build is not the end of the story. You've also got to package your code up as an Android -APK. For that you can use [cargo-apk]. I'm not going to show you that -now because I haven't yet worked through those steps myself. +APK. For that you can use [cargo-apk]. [cargo-apk]: https://users.rust-lang.org/t/announcing-cargo-apk/5501 - - - - - - - - - ## Rust everywhere else Rust is a software platform with the potential to run on anything with From b1ee9c9018d3347d07ffbfe32d0bd1a16cc80bab Mon Sep 17 00:00:00 2001 From: Corey Farwell Date: Fri, 13 May 2016 18:01:10 -0400 Subject: [PATCH 241/386] =?UTF-8?q?Fix=20typo:=20'queue'=20=E2=86=92=20'cu?= =?UTF-8?q?e'.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- _posts/2016-05-13-rustup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-13-rustup.md b/_posts/2016-05-13-rustup.md index ecfcc5053..6c11dabfd 100644 --- a/_posts/2016-05-13-rustup.md +++ b/_posts/2016-05-13-rustup.md @@ -243,7 +243,7 @@ The error tells us that the compiler can't find `std`. That is of course because we haven't installed it. To start cross-compiling, you need to acquire a standard library for the target -platform. Previously, this was an error-prone, manual process — queue those +platform. Previously, this was an error-prone, manual process — cue those blog posts I mentioned earlier. But with rustup, it's just part of the usual workflow: From 9cfe9a76dc204cb60054beb185ec6a579a23fed4 Mon Sep 17 00:00:00 2001 From: Tshepang Lekhonkhobe Date: Sat, 14 May 2016 00:47:34 +0200 Subject: [PATCH 242/386] Update 2016-05-13-rustup.md typo --- _posts/2016-05-13-rustup.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2016-05-13-rustup.md b/_posts/2016-05-13-rustup.md index 6c11dabfd..b2262b138 100644 --- a/_posts/2016-05-13-rustup.md +++ b/_posts/2016-05-13-rustup.md @@ -109,7 +109,7 @@ That's an easy way to verify your code works on the next Rust release. That's good Rust citizenship! We can use `rustup show` to show us the installed toolchains, and `rustup -update` to keep the up to date with Rust's releases. +update` to keep them up to date with Rust's releases.