Currently, in Rust variables hoist, just as in JavaScript. I would like to propose removing this feature, and having each "let" introduce a new scope.

Here is a use case, in trans:

fn trans_foo(&bcx : @block_ctxt) -> @block_ctxt {
    ... do something with bcx ...

    let new_bcx = new_sub_block_ctxt(bcx);
    bcx.build.Br(new_bcx);
    let bcx = new_bcx;

    ... use bcx ...
}

The reason for this is to prevent any usage of the old "bcx" after building the branch instruction via shadowing. This helps prevent errors, because once a basic block is terminated it is an error to build any more instructions in it.

It is not possible to do this in Rust at the moment:

* The "bcx" variable declaration hoists to the top of the block, making it impossible to refer to the parameter at all. Typestate will catch any use of "bcx" before it's initialized, but the error message is still surprising, and worse, it makes it impossible to do what I want here.

* I can't just mutate "bcx", because it's an immutable alias.

* I could simply refer to "new_bcx" exclusively and avoid the shadowing declaration, but then I lose the safety guarantee that I wanted: it's possible (and anyone who has hacked on trans knows that it's a very common error) to accidentally build instructions on "bcx" instead of "new_bcx".

To me, this is not only an issue of avoiding surprises by doing what every other language but JavaScript does, but also an issue of safety. Shadowing can be a useful tool to enforce safety guarantees in the small.

Other, weaker but still compelling arguments in my mind:

This code compiles but is awfully confusing:

fn main() {
  x = 3;
  log_err x;
  let int x;
}

This code gives a typestate error instead of working as intended:

fn f(int x) {
    log_err x;
    auto x = 3;
}

Opinions?

Patrick
_______________________________________________
Rust-dev mailing list
[email protected]
https://mail.mozilla.org/listinfo/rust-dev

Reply via email to