Hi Brian, Thanks so much for your detailed reply. On Tue, Sep 11, 2012 at 6:43 AM, Brian Anderson <bander...@mozilla.com> wrote: > I'll mention that both the pattern matching and closure syntaxes are very > cramped, with a lot of competing requirements.
Yes, I can imagine. In particular, I imagine that being relatively terse is one them, given that pattern matching and closures will be frequently-used parts of the language. I was mindful of the number of typed characters in what I was proposing. However, it's precisely due to the importance of these language features (which was apparent to me as I read the Tutorial) that I think these features should be non-scary (to newcomers) and non- error-prone (to less-experienced programmers). > I think that most people will see this as too verbose, but I am sort of > warming to this and the reason is `ref`. Currently, patterns implicitly bind > by reference, but in the future they will create a copy, and to bind a > reference you will need to write `ref`, as in `(0f, ref y) =>`. This is the > only place that `ref` exists in the language. Saying that a binding is > always introduced using either `let` or `ref` at least makes `ref` not stand > out as bad. Of course, to be consistent with the goal of always using `let`, > we would probably have to use `let ref` and then we're sort of back in the > same spot. Ah, this is very interesting, thanks for this. I've been thinking about pointers and references in Rust quite a bit recently, to ensure I have a clear understanding of '&' in particular, especially as I've digested the points made in the recent "weirdness of strings" thread: https://mail.mozilla.org/pipermail/rust-dev/2012-September/002315.html After a bit of thought about this 'ref' keyword, and the 'let ref' issue you point out, it would seem completely reasonable to me for Rust to have mutually-exclusive 'let' and 'ref' keywords, just as there is a separate 'const' keyword. So it would be 'ref y', not 'let ref y'. 'ref' could potentially be defined generally (i.e., able to be used outside pattern matching) as "introduce a binding that simply acts as an alias to an existing storage unit on the stack", in contrast to 'let' as "introduce a binding and allocate a new storage unit on the stack and copy the r-value". This 'ref' keyword would also seem to me to be a better fit than 'let' for the named parameters of closures. (Initially, I thought 'let' would be more appropriate, since a non-stack closure might outlive the current stack. But on further thought, I realised that any other local variables referenced inside the closure are not specifically "re-let", but are instead copied implicitly based upon the type of the closure. So it would be reasonable to use 'ref' for the named parameters and copy them implicitly too if the type of the closure specifies it.) > OK, so how do let bindings work under this scheme? Here's current syntax: > > let (foo, bar) = baz(); > > Any irrefutable pattern can go after 'let'. So does that become: > > let (let foo, let bar) = baz(); > > Just writing `(let foo, let bar)`, allowing patterns to begin statements, is > probably unparseable. Since tuple destructuring occurs as a stand-alone statement outside of a pattern matching construct, it would seem quite reasonable to me for the lang spec to simply define that in this particular situation, the syntax is: let (foo, bar) = baz; If the inevitable question-asking idealists such as myself ask why the syntax isn't the slightly more-consistent: (let foo, let bar) = baz; , I think it would be quite reasonable to say "because it's a stand-alone statement, so that wouldn't parse, so instead we do it this way". In such a situation, I'd accept that as an answer. The presence of a 'let' keyword to indicate new variable bindings would keep me happy; and of course no-one who's actually planning on typing this every day would insist upon additional 'let' keywords inside the tuple when there's already a 'let' keyword immediately in front. I think it's worth pre-emptively clarifying the distinction in my mind between this tuple destructuring situation vs the partially-literal destructuring pattern and the struct destructuring pattern. I would argue there's no need to target specific variables in the tuple destructuring (using immediately-preceding 'let'/'ref' keywords) because all the variables in the tuple are being bound and there are no other identifiers or tokens in there. To me, this contrasts with a partially-literal destructuring pattern (where only some of the tuple members are variables that are being bound, while other tuple members are literals or enums) and a struct destructuring pattern (in which the 'let'/'ref' keyword needs to be precisely located, to differentiate the newly-bound variable name from the struct field name). > I would want to still have the option if inferring the storage for the > closure, like `do foo.each (let n) => {`. I wouldn't have any objections to this. As I mentioned in my reply to Kevin, I included the '&' because I was reproducing the examples as closely as possible. I have no specific argument for or against the use of the '&'. > I do think the 'let's here make the syntax not that aesthetically pleasing. > Also the parens for closure syntax make this harder for eyeballs to parse. I actually find the parentheses easier to eyeball-parse as "inside vs outside the parameter list" than the directionless pipe sigils. > do foo.each(bar) (let baz) => { > > The argument lists look pretty similar. > > Also: > > do foo.each() () => { > do foo.each () => { > > Weirdness. I haven't seen any examples in the Tutorial or Reference Manual where 'each' is a method rather than a stand-alone function. Would you have any pointers to docs that I could read about this? In particular, what are 'foo' and 'bar' in the above example? Thanks again for your very detailed reply. Sorry for sending you even more to read from me now. :) jb _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev