[rust-dev] Brace-free if and alt

Niko Matsakis niko at alum.mit.edu
Thu Apr 12 10:33:02 PDT 2012


I am not a big fan of the `if` syntax.  Or at least I don't mind our 
current one and it is nicely unambiguous.  However, I really like "alt 
with arrow" syntax.  I find the current one quite unreadable, 
particularly for long blocks.  The "=>" arrow (or `->`, I am somewhat 
indifferent) helps to set apart the conditions and the blocks.

Here is a random example to illustrate what I mean:

Before:

>             alt elsopt {
>               some(els) {
>                 let if_t = fcx.next_ty_var();
>                 let thn_bot = check_block(fcx, thn);
>                 let thn_t = fcx.node_ty(thn.node.id);
>                 demand::simple(fcx, thn.span, if_t, thn_t);
>                 let els_bot = check_expr_with(fcx, els, if_t);
>                 (if_t, thn_bot & els_bot)
>               }
>               none {
>                 check_block_no_value(fcx, thn);
>                 (ty::mk_nil(fcx.ccx.tcx), false)
>               }
>             };

After:

>             alt elsopt {
>               some(els) => {
>                 let if_t = fcx.next_ty_var();
>                 let thn_bot = check_block(fcx, thn);
>                 let thn_t = fcx.node_ty(thn.node.id);
>                 demand::simple(fcx, thn.span, if_t, thn_t);
>                 let els_bot = check_expr_with(fcx, els, if_t);
>                 (if_t, thn_bot & els_bot)
>               }
>               none => {
>                 check_block_no_value(fcx, thn);
>                 (ty::mk_nil(fcx.ccx.tcx), false)
>               }
>             };

I personally find the second example quite a bit easier to read.  In the 
first, my eyes get lost and I have trouble distinguishing the patterns 
from the code.

It is also much nicer for small alts, for example:

>         let pass1 = alt ty::get(self.self_ty).struct {
>           ty::ty_param(n, did) {
>             self.method_from_param(n, did)
>           }
>           ty::ty_iface(did, tps) {
>             self.method_from_iface(did, tps)
>           }
>           ty::ty_class(did, tps) {
>             self.method_from_class(did, tps)
>           }
>           _ {
>             none
>           }
>         };

becomes:

>         let pass1 = alt ty::get(self.self_ty).struct {
>           ty::ty_param(n, did) => self.method_from_param(n, did)
>           ty::ty_iface(did, tps) => self.method_from_iface(did, tps)
>           ty::ty_class(did, tps) => self.method_from_class(did, tps)
>           _ => none
>         };

So I propose we make the syntax for an alt arm be:

     alt := `alt` expr { arm* }
     arm := pattern => expr


Niko

On 4/11/12 1:28 PM, Patrick Walton wrote:
> Here's a total bikeshed. Apologies in advance:
>
> There's been some criticism of Rust's syntax for being too 
> brace-heavy. I've been thinking this for a while. Here's a minimal 
> delta on the current syntax to address this:
>
> Examples:
>
>     // before:
>     if foo() == "bar" { 10 } else { 20 }
>
>     // after:
>     if foo() == "bar" then 10 else 20
>     // or:
>     if foo() == "bar" { 10 } else { 20 }
>
>     // before:
>     alt foo() {
>         "bar" { 10 }
>         "baz" { 20 }
>         "boo" { 30 }
>     }
>
>     // after:
>     alt foo() {
>         "bar" => 10,
>         "baz" => 20,
>         "boo" => 30
>     }
>     // or:
>     alt foo() {
>         "bar" { 10 }
>         "baz" { 20 }
>         "boo" { 30 }
>     }
>
> BNF:
>
>     if ::== "if" expr ("then" expr | block) ("else" expr)?
>     alt ::== "alt" expr "{" (arm* last-arm) "}"
>     arm ::== block-arm | pat "=>" expr ","
>     last-arm ::== block-arm | pat "=>" expr ","?
>     block-arm ::== pat block
>
> You can think of it this way: We insert a "then" before the 
> then-expression of each if; however, you can omit it if you use a 
> block. We also insert a "=>" before each expression in an alt arm and 
> a "," to separate expressions from subsequent patterns; however, both 
> can be omitted if the arm expression is a block.
>
> This does, unfortunately, create the dangling else ambiguity. I'm not 
> sure this is much of a problem in practice, but it might be an issue.
>
> The pretty printer would always omit the "then" and the "=>"/"," when 
> the alt arm is a block. That way, we aren't introducing multiple 
> preferred syntactic forms of the same Rust code (which I agree is 
> generally undesirable); the blessed style is to never over-annotate 
> when a "then" body or an alt expression is a block.
>
> Here's an example piece of code (Jonanin's emulator) written 
> before-and-after:
>
> Before: https://github.com/Jonanin/rust-dcpu16/blob/master/asm.rs
> After: https://gist.github.com/2360838
>
> Thoughts?
>
> Patrick
> _______________________________________________
> Rust-dev mailing list
> Rust-dev at mozilla.org
> https://mail.mozilla.org/listinfo/rust-dev



More information about the Rust-dev mailing list