6 ms·
This strikes me as a bad idea prone to action-at-a-distance. let a = 1 let b = pointer to a do_stuff(b) do_other_stuff (a) is legal but suddenly becom
by JulianMorrison 11y ago
This strikes me as a bad idea prone to action-at-a-distance.
let a = 1
let b = pointer to a
do_stuff(b)
do_other_stuff (a)
is legal but suddenly becomes illegal when you turn it into
let a = 1
let b = pointer to a
do_stuff(b)
do_other_stuff (a)
// ... etc etc
do_more_stuff(b)
You add a legal statement down the function for a variable that's still valid and in scope, and the calls above it go kablooey.
- the_mitsuhiko 11y agoThat is already the case anyways.
- JulianMorrison 11y agoIf I understand the article, what's already the case is that any reuse of "a" while "b" exists is illegal. Which is simple and uncomplicated and you can work around it like this let a = 1 begin block scope { let b = pointer to a do_stuff(b) } // end block scope and b is dead do_other_stuff (a) What the change would do is make that block scope exist, but it exists implicitly and invisibly. And it invisibly stretches over the call to do_other_stuff(a) by the insertion of the do_more_stuff(b) below it. And suddenly it breaks. Contrast: let a = 1 begin block scope { let b = pointer to a do_stuff(b) } // end block scope and b is dead do_other_stuff (a) // ... etc etc do_more_stuff(b) // is obviously broken, b is not in scope or let a = 1 begin block scope { let b = pointer to a do_stuff(b) do_other_stuff (a) // is obviously broken, b is not dead // ... etc etc do_more_stuff(b) } // end block scope way down here
- kibwen 11y agoGiven that the Rust team is committed to introducing non-lexical lifetimes backwards-compatibly, by definition that means that no code that compiles today will be invalidated by the feature's addition. Which means that the only instances of concern being raised here are programs which are already invalid in today's Rust, which is to say that any workarounds for these theoretical problems are already mandatory. There's nothing "breaking" here that isn't already broken. It's a strict reduction in the number of programs that will be rejected by the borrow checker.
- askyourmother 11y agoAgreed - not sure this is a good thing, making code and actions harder to reason about. Another reason to reconsider Rust...
- dbaupp 11y agoI don't think non-lexical lifetimes will make code harder to reason about (beyond the fact that it means there are more valid Rust programs, of course), because it doesn't change behaviour: a program that currently compiles won't have different runtime results with non-lexical lifetimes. I suppose it will mean a programmer might have to think a little harder if they want to manually preempt compilation errors, but fortunately the compiler is there to catch them if they don't get it right. The example the OP points out is a situation that will likely play out like the following in most circumstances: - programmer adds new use of variable b. - compiler points out an existing use of some other value a that could invalidate b, and, importantly, highlights all the moving parts (conflicting use of a, use of b that prolongs its lifetime, etc.) in the error message. - programmer edits code to avoid the problem.
- jerf 11y agoYou do this exact thing all the time in non-Rust languages. Rust notices, and then tells you about it. I don't think that makes code harder to reason about... I think that leans more in the "easier" direction. I don't think you should dock Rust for pointing out bad practices that other languages simply don't notice. I think you can dock it for complaining about code that's really OK, which just happens to be exactly what they're trying to fix here.
- geofft 11y agoSo, I don't endorse this reasoning, but I can see it. With Rust you have to think about the possible failure cases of your code up-front and account for them. In other languages, you don't have to. For instance, I'd bet that most C or C++ apps in production that use concurrency have some concurrency bug somewhere, that's so rare that nobody has hit it yet (or the effect of the bug is minor). Those apps are running in production and serving a valuable purpose. Rust would force you to solve the edge case before deploying the app in production. Occasionally, it's the right set of engineering tradeoffs to deploy something that produces useful results 99.9% of the time and crashes .1% of the time. (But, I guess you can say, you can always use Rust's 'unsafe' keyword to acknowledge that something isn't quite right but you're deploying it anyway.)
- dbaupp 11y agoThis is exactly one example why non-lexical lifetimes aren't a uniform positive: they do make the compiler more accepting of code that people think should "obviously" compile, but comes at the cost of weird situations where making a (somewhat) distant change results in errors. Fortunately, these sort of errors should be all function-local and are of course all flagged at compile time. Assuming Niko's usual focus on high-quality error messages continues, I would expect this sort of situation to be fairly clearly explained by the compiler.
- sixbrx 11y agoI don't know, borrow checker error messages are already pretty good at pointing out issues of this sort already. With a minor addition I think it would remain very comprehensible: "you borrowed a here ^^^ ... gave a away here ^^^^, then used it's borrow again here ^^^^ after having given it away."
- baq 11y agowell that's the point.
- jerf 11y agoI'd submit that stretching "action at a distance" to include "function local" is really taking the idea too far. When we decry "action at a distance" I don't think we generally mean "seventeen lines previous in the same function". I think we also generally mean "action at a distance that produces hard-to-debug runtime effects", not "compiler errors that point out exactly what is wrong on what line" (as I assume will be the case).
- pcwalton 11y agoWell, then you get an error for a valid reason, as opposed to always getting an error for a bogus reason. False positives aren't a good thing!
- kibwen 11y agoGiven that this always results in a clear compilation error, it'd be more accurate to call this "inaction-at-a-distance". :P