First off, Masklinn thanks for your feedback (I know others have said
it, but I wanted to chime in). This kind of thing is inordinately useful.
*pcwalton: *Nobody could find a way to implement non-local returns in
a performant way, so they're missing. There's been discussion of a
magic "loopctl" enum type as a return type for blocks, which would
allow non-local returns with cooperation between the loop function and
the block.
I finally got around to writing up my idea
<https://github.com/mozilla/rust/issues/1619>. It's not full-on
smalltalk blocks but it would be straightforward to implement and nice
to have. Worse is better and all that.
*OP: ** The second issue is both trivial and extremely serious: after
having written a few trivial pieces of code (can't call them
programs), it feels like Rust's handling of semicolons combines
the simplicity of Erlang's with the determinism of
Javascript's.
I think the criticism is fair enough---even though I authored the
current rules I am not sure they are best, though I prefer them to what
we had before---but I do want to point out that the rules are not
non-deterministic or anything like that. In fact, I made a big effort
to ensure that programs which are not parsed "as they appear" will
result in compile errors.
For example, something like this:
fn foo(v: [int]) -> int {
vec::foldl(v, 0, {|x, y| x + y}) - 10
}
looks like it sums up all of the integers in the list and subtracts 10,
but in fact it parses as:
fn foo(v: [int]) -> int {
vec::foldl(v, 0, {|x, y| x + y}) // throw away the return value
-10
}
This would seem like a big problem, except that the type checker will
report an error because vec::foldl() has a non-unit return type and an
omitted semicolon. Of course, if you're the innocent author who doesn't
realize WHY you're getting an error, it can still be quite confusing!
Personally I think we were going to change the current rules I would
want to just use a semicolon consistently after every statement, whether
or not a similar statement would have a semicolon in C. So you would write:
fn foo() { ... } // this is a declaration, no semicolon
while test { ... }; // this is a statement, use a semicolon
ret foo;
and so forth. I would probably also make the trailing semicolon
insignificant, as discussed below. As pcwalton said, though, this would
mean that we feel "even less" like C.
*pcwalton: *I like OCaml's solution, which is to simply ignore
trailing semicolons. In order to do this we need to reform the
standard library to avoid returning values that are unused (which is a
good idea anyway, so this is a lesser problem). But IIRC when this was
tried, there were parsiing ambiguities involving loops and sugared
block syntax (basically, the set of expressions that automatically
infer a trailing semicolon). We would have to solve those issues somehow.
Actually, the parser was not the problem. In fact, the parser does not
currently look "inside" blocks and that sort of thing like it used to.
The problem was that I tried to change the representation of a block
from a pair of (stmts, tail expr) to just (stmts), and this triggered
lots of changes. If I were to try again, I think I would keep block the
way it was.
What is needed, however, is a change to the type checker which says that
tail expressions in a unit return context are effectively ignored. In
other words, I think that a function like:
fn bar(...) -> int { /* some side effect-y thing */ }
fn foo(...) {
bar(...);
}
should still type check, but if we get overeager on the unification it
will not. I also made this change to the type checker. It was minor.
It seemed to work fine. I'm sure it might give a somewhat surprising
error in some corner cases, like blocks where we are inferring the
return type (those need work anyhow), but that's probably ok.
In the end, though, I decided to go the more conservative route and not
modify the type checker but instead simply require that statements
without a trailing semicolon must have unit type.
All that said, I think what the OP was complaining about was not knowing
when a semicolon is required and when it is not. This can be a bit
confusing. The rule is more-or-less "if it ends with braces, it does
not need a semicolon", but this is not true when e.g. the expression is
embedded in a `let` (as, then, the `let` itself needs a semicolon).
So the following are fine and do not require semicolons:
foo() {|| ... }
if ... { ... } else { ... }
but this does:
let x = foo() {|| ... };
*OP: ** Finally, I could not find any good information on the result
of loop
expressions, from my tests it seems to always be `()` is that
correct? If so, why `()` rather than the last-evaluated result of
the iteration? In case no iteration at all is performed?
By the by, I believe that do-while loops return the value of the final
iteration (they always have at least 1).
Niko
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev