5 ms·
I'm very happy to see Rust stabilize, about time we get a systems(ish) programming language with a half decent type system. With that said... I need to get som
by drobilla 12y ago
I'm very happy to see Rust stabilize, about time we get a systems(ish) programming language with a half decent type system. With that said... I need to get some bikeshedding off my chest:
I hate to let such a triviality lower my enthusiasm for a language so much, but I just can not get over that awful inconsistent closure syntax :/
I don't get it. Most everything else has a nice unique keyword syntax, fn uses (args, in, parenthesis), proc syntax made consistent sense, then lambda is this crazy || linenoise thing that doesn't fit in at all. The "borrow the good ideas from other languages" approach has resulted in a great language, but "cram random syntax from other languages that doesn't fit" doesn't work out so well.
- steveklabnik 12y agoAs a Rubyist, I found the closure syntax quite comfortable, as they're almost identical. Passing a closure or lambda to some function foo: x = foo {|x| x + 1 } # Ruby let x = foo(|x| { x + 1 }); //Rust let x = foo(|x| x + 1 ); // single expressions don't need {}s That said, I'm not sure what the exact reason was for choosing the syntax, as that was before my time.
- aturon 12y ago> That said, I'm not sure what the exact reason was for choosing the syntax, as that was before my time. I think the reason is just that it's very concise, and lightweight closure syntax makes things like `Option::map` feel like first-class parts of the language. The closure you pass just sort of seamlessly "blends in". Note that having especially sugary here is not so uncommon, for example Haskell has `\x -> blah` for Rust's `|x| blah`. I'm personally very happy that the closure syntax is as concise as it is.
- pcwalton 12y agoThe natural thing to want in a C-like syntax is the "arrow function" closure syntax (like ES6 or C#), but that required too much lookahead to parse. Having a keyword discourages functional style, which would be a shame in a language with a powerful iterator library. So Rust went with the Ruby/Smalltalk-style bars, which are nice, concise, and easy to parse.
- alextgordon 12y agoIt seems like the human parser should be given priority over the computer parser, when considering what is easy and what is hard. The machines work for us!
- kibwen 12y agoThis human parser happens to prefer Rust's closure syntax to any other language's. :) Well, for usage, anyway... the written-out type of a closure for use in function signatures is not nearly as concise.
- gnuvince 12y agoAs far as I know, Rust now has an LL(1) grammar, which means that writing parsers for it can be done by hand (or with the more powerful LALR(1) and LR(1) parser generators). This is very important for humans too, because it means more people are likely to write tools to process Rust code. If you hope to have automatic indentation, auto-completion, refactoring, formatting tools, etc. keeping the syntax simple is really important.
- nostrademons 12y agoCan't they just expose the parser as a library? Actually, it looks like they did, with the rustc crate. Hand-writing a parser for some other language leads to madness - just ask the folks who've done SWIG, GDB, or most IDE syntax-checkers. You'll inevitably get some corner-cases wrong, or the language definition will change underneath you long after you've ceased to maintain the tool. Instead, the language should just expose its compiler front-end as a library, and then you can either serialize the AST to some common format for analysis outside the language or build your tools directly on top of that library.
- jpgvm 12y agoYou missed the whole point. By making the language simple you can easily implement your own parser. This opens up the ability to write native parsers in other languages, say vimscript. By keeping it super simple there -are- no corner-cases. There are many benefits to this (like the formatters etc that others have alluded to) from things like IDE integration (imagine lifetime elision visualisation, invalid move notifications, etc) static analysis tools and more. None of these tools then need to be written in Rust. It also means it's easier to implement support in pre-existing multi-language tools. Don't underestimate the necessity of a simple parseable grammar. Besides, people have endured much worse slights in syntax (see here Erlang).
- doctoboggan 12y agoI am not a Rust user and maybe I am reading the post wrong but it seems that syntax has been deprecated: > Closures: Rust now supports full capture-clause inference and has deprecated the temporary |:| notation, making closures much more ergonomic to use.
- yuriks 12y agoWhat was deprecated is the explicit closure type specification, which is only the ":" part.
- comex 12y agoRight. IIRC, now your choices are, roughly: |args| expr // upvars captured by reference, can't be called after function has gone out of scope move |args| expr // upvars moved from function to the closure context (or copied if trivially copyable) This is simple and good enough for most use cases. If you want more complex schemes, you have to implement them manually, e.g. to reference count the upvars, like Apple blocks do by default, wrap them in Rc and capture that. Accepting closures is a bit more complicated though.
- aturon 12y agoThat's not quite right. In the non-move case, the capture is inferred per upvar. See my other comment for details (https://news.ycombinator.com/item?id=9047766 https://news.ycombinator.com/item?id=9047766)
- mbrubeck 12y agoThat's talking about something different. For a brief period, closures had to be annotated in certain cases like |&: args| or |&mut: args| or |: args| to determine whether they captured their environment by (mutable) reference or by value/move. Now that this is inferred in all cases, closure arguments can just be written as |args| in all cases, just as they were before the current Fn* traits were introduced.
- 12y ago