I prefer option #3, just according to taste. froy
On Tue, Nov 23, 2010 at 2:58 PM, David Herman <[email protected]> wrote: > Two afterthoughts: > > - IINM, the different syntax for blocks between option #2 and option #3 is > not that drastic, so if we choose one and decide we prefer the other, it > might not be too hard to change. > > - In option #4, we can't completely *turn off* typechecking -- that's > unsound. (For example, inside the unchecked part you could assign the wrong > type to a variable or data structure.) But we could avoid certain checks > (like comparing the result type of the two arms of an if). Not that I'm > advocating option #4. :) > > Dave > > On Nov 23, 2010, at 2:53 PM, David Herman wrote: > > > Of these, I like option #3 the most. > > > > I should say, I think anywhere that we have statements in the grammar, we > could actually allow them to be expressions of type (), and ISTM that would > be equally workable for option #2 or option #3. I'd be open to that > alternative, since in *surface* syntax you still have the look and feel of > C, but you get higher refactoring flexibility. > > > > Dave > > > > On Nov 23, 2010, at 2:34 PM, Graydon Hoare wrote: > > > >> Hi, > >> > >> Some of you may have noticed that in the rewrite from rustboot to rustc > we're becoming substantially more expression-language-ish. This is mostly a > result of me yielding to the preferences of other developers (and LLVM's > semantics), as well as some hint that things get much easier in syntax > extensions and calculating compile-time-constants if we permit more > "statement-ish" forms as expressions. Particularly conditionals. > >> > >> We've run into a (common, seen in many other languages) sort of problem > along the way here, which is that some expressions are implicitly ignored > (or must be, due to being in an ignored context) whereas others are not. We > have a nil-type (), but we don't always have sensible rules for forcing > things to have the nil type by context. > >> > >> This email is a poll of alternative solutions. I'll give two example > cases and ask people for their input on which modification of the rules > feels best. > >> > >> Example case that does compile: > >> > >> A: auto x = if (foo()) { 10; } else { 11; }; > >> > >> Example case that does not compile: > >> > >> B: if (foo()) { 10; } else { "hello"; } > >> > >> We can write this in rust at the moment, but in the rustc typechecking > rules it will fail to compile, because 'if' is an expression-statement, > expressions have types, and the types of the two branches (judged as the > last statement's expression value, if it's an expression, or else nil) are > of different types. > >> > >> Here are some approaches to solving this example. Please pick the one > you like the most: > >> > >> (1) Kick all branchy expressions out of the expression grammar, put them > back in the statement grammar. Case B will compile, and case A must be > rewritten like so: > >> > >> A: auto x = { auto t = 11; if (foo()) { t = 10; }; t; }; > >> > >> This is the C-with-GNU-extensions model. > >> > >> (2) Hoist all statements up into the expression language and make > semicolon into a sequencing operator, with a trailing-semi ignored by the > parser. Then we need to rewrite only the second case to force unit types in > the to-be-ignored differing branches. > >> > >> B: if (foo()) { 10; () } else { "hello"; () } > >> > >> Though we'd also be *allowed* to rewrite the first case to drop the > semicolons: > >> > >> A: auto x = if (foo() { 10 } else { 11 }; > >> > >> This is the Ocaml approach. > >> > >> (3) A slightly weaker form of (2), which is to reformulate blocks with > the following grammar: > >> > >> block ::= { [ stmt ; ]* expr? } > >> > >> In other words, every block becomes a brace-enclosed sequence of > semicolon-terminated statements, followed by an optional expr. If the expr > is missing, it is implied as (). In this case we'd be rewriting only the > first case: > >> > >> A: auto x = if (foo()) { 10 } else { 11 }; > >> > >> This is similar to the Ocaml rule in practice, except that it makes the > presence or absence of the final semicolon in a block equivalent to ending > the block with the nil type. This is a possible hazard (especially during > refactoring or editing) to users who want to write a value-producing block > but accidentally semicolon-terminate the last expression; but it's not a > huge hazard since the typechecker will tell them the value they produced is > of nil type. It just might be hit a lot. > >> > >> (4) Statically determine the contexts in which an expression's value > "will be used" in an outer expression, and only typecheck those contexts. > This permits both of the examples to compile as-is, but it's the most > unorthodox approach, and poses a refactoring hazard as code may become > type-invalid when nested into an expression context that "uses" its > previously-ignored result. Again, as in (3) the typechecker will catch these > cases, but they might happen more or less often than those in (3). > >> > >> We can't think of any other options. Significant whitespace is not an > option :) > >> > >> Personally my knee-jerk reaction is to embrace (1) since I like > statements anyway, but I can see plausible arguments for the other 3. Can I > get a show of hands? We have to pick something. > >> > >> -Graydon > >> _______________________________________________ > >> Rust-dev mailing list > >> [email protected] > >> https://mail.mozilla.org/listinfo/rust-dev > > > > _______________________________________________ > > Rust-dev mailing list > > [email protected] > > https://mail.mozilla.org/listinfo/rust-dev > > _______________________________________________ > Rust-dev mailing list > [email protected] > https://mail.mozilla.org/listinfo/rust-dev >
_______________________________________________ Rust-dev mailing list [email protected] https://mail.mozilla.org/listinfo/rust-dev
