Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
Hi, Am 02.01.2014 um 07:18 schrieb Patrick Walton pcwal...@mozilla.com: And that's just a simple example: start throwing in existential types like traits and it becomes clear that you really can't tell from the program where mutation could possibly happen, because the types are hiding mutability from you. And that's fine--existential types and generics deliberately permit that abstraction. But it does mean, I think, that we can't meaningfully talk about a sound and complete mut annotation at call sites. Maybe completely off here but why is mutability not tracked by the region system? Wouldn’t that help solve this issue? i.e. assignment to a mutable lvalue would only be allowed from an rvalue in a mutable region. Haven’t thought about how that relates to freezing/thawing. Cheers, Stefan ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On 1/3/14 2:25 AM, Stefan Plantikow wrote: Maybe completely off here but why is mutability not tracked by the region system? Wouldn’t that help solve this issue? i.e. assignment to a mutable lvalue would only be allowed from an rvalue in a mutable region. Haven’t thought about how that relates to freezing/thawing. It kind of is, in that mutation generally requires a unique ownership path. See the comments in the borrow checker for more details. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
Thanks, that explains it.Martin - Original Message - From: Patrick Walton And that's just a simple example: start throwing in existential types like traits and it becomes clear that you really can't tell from the program where mutation could possibly happen, because the types are hiding mutability from you. And that's fine--existential types and generics deliberately permit that abstraction But it does mean, I think, that we can't meaningfully talk about a sound and complete mut annotation at call sites. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
I'd say it should be i(mut x, ...), though in this case inferring borrow is not possible because of the lambda. But if this were a standalone function, e.g. the f() above, one could write i(mut x, f); Regarding mutation-polymorphic generics, yes, it may not be possible to mut-annotate them. I would just let it slide for pass-through types like T, but require annotations in non-generic code. Not the best solution, but it just bothers me that we worry about the mutability hazard at the top level of the call chain, but then completely forget about it inside the callee. Vadim On Wed, Jan 1, 2014 at 10:18 PM, Patrick Walton pcwal...@mozilla.comwrote: On 1/1/14 10:06 PM, Vadim wrote: Well, since requiring '' at the original borrow site doesn't really prevent the unexpected mutability problem, why not drop it and eliminate a bunch of noise from Rust sources? But it does eliminate mutation of lvalues. And, again, if unexpected mutability is what concerns people, mut annotation is the better way to fix that, IMHO. I don't know if it's a coherent proposal. Consider these four function signatures, each of which might mutate their arguments: fn f(x: mut int) { ... } fn g(x: (mut int, mut int)) { ... } struct S'a { a: 'a mut int, b: 'a mut uint, } fn h(x: S) { ... } fn iT(x: T, f: |T|) { f(x) } How might `i` mutate its argument? Consider function `j`: fn j() { let mut x = 3; i(mut x, |ptr| *ptr = 5); } So `i` mutated its argument. So how should you be forced to notate that? Should you have to write: fn iT(x: T, f: |T|) { f(mut x) } ... i(mut x, |ptr| *ptr = 5); Or: fn iT(x: T, f: |T|) { f(x) } ... i(mut mut x, |ptr| *ptr = 5); Or: fn iT(x: T, f: |T|) { f(mut x) } ... i(mut mut x, |ptr| *ptr = 5); And that's just a simple example: start throwing in existential types like traits and it becomes clear that you really can't tell from the program where mutation could possibly happen, because the types are hiding mutability from you. And that's fine--existential types and generics deliberately permit that abstraction. But it does mean, I think, that we can't meaningfully talk about a sound and complete mut annotation at call sites. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On 1/1/14 3:49 PM, Martin Olsson wrote: For example in C the call f(a,b); might modify b but not a so the token acts as a call site heads-up flag when reading the code. Same in Rust. In C# the out/ref keywords are mandatory at the call site if the callee uses them in its param declaration so there you also get a little in hint when reading the code near the call site. C# has neither first-class pointers nor first-class references, so it isn't really a comparison. C++ of course has non-const references so f(a,b); might modify both a and b so the hint is missing and I really have to look up the code for f() to be sure. If some function foo() passes a to a bunch of functions then I have to find each such function and check if a can be modified or not, so potentially I have to open a bunch of files and read code there before I can fully understand the code near the call sites. That's right, and that's why Rust doesn't do this. Because of this many large C++ projects have coding styles that disallow non-const refs. See for example the google C++ coding style guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone=Reference_Arguments#Reference_Arguments Google's style guide allows mutable pointers, which are more like Rust references in this regard (except that pointers can be null in C++ and can't in Rust). Right now, it seems that rust works similar to C++ in this regard, meaning that there is no hint at the call site that a parameter may or may not be modified by the function. No, Rust works like *C*, where if you pass a mutable *pointer* that was already mutable down a call chain then the callee can mutate it. What C++ allows you to do that these style guides are trying to forbid is to pass an *lvalue* to a function and to have that function able to mutate that lvalue. That is not allowed in Rust. In the snippet below, if I'm reading foo() in main.rs and I wonder which lines in foo() could possibly change the value of i, then I have to open up 4 additional files and find the relevant source locations to double check which functions might mutate their arguments. You already had a mutable pointer; you can pass that mutable pointer down the call chain. Why isn't it a good idea to require some parameter prefix like mut at the call site so that when I read main.rs I immediately will know which lines among the calls to funcA()..funcD() that might change the value of i ? Because that would work completely like any other language with pointers that I know of. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On 1/1/14 3:55 PM, Patrick Walton wrote: Because that would work completely like any other language with pointers that I know of. Err, I mean unlike. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On Wed, Jan 1, 2014 at 6:49 PM, Martin Olsson mar...@minimum.se wrote: Short version of my question: Why doesn't rust require mut param prefix at call sites? i.e. to avoid non-const ref badness that C++ has? Well, to be somewhat extreme, in a function like struct S { a: mut int, b: mut int } fn f(s: mut mut S) ... fn g(s: mut mut S) { f(s) } what sort of muts does g need? ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
I think the real answer is at this point nobody wants to tweak basic Rust syntax yet again. See the other thread about Rust roadmap, etc. Oh well... On Wed, Jan 1, 2014 at 3:49 PM, Martin Olsson mar...@minimum.se wrote: Short version of my question: Why doesn't rust require mut param prefix at call sites? i.e. to avoid non-const ref badness that C++ has? Longer version of my question: Since this question was asked recently by vadim and not really answered clearly (imo), I'm also including this longer verbose version of my question. For example in C the call f(a,b); might modify b but not a so the token acts as a call site heads-up flag when reading the code. In C# the out/ref keywords are mandatory at the call site if the callee uses them in its param declaration so there you also get a little in hint when reading the code near the call site. C++ of course has non-const references so f(a,b); might modify both a and b so the hint is missing and I really have to look up the code for f() to be sure. If some function foo() passes a to a bunch of functions then I have to find each such function and check if a can be modified or not, so potentially I have to open a bunch of files and read code there before I can fully understand the code near the call sites. Because of this many large C++ projects have coding styles that disallow non-const refs. See for example the google C++ coding style guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone= Reference_Arguments#Reference_Arguments Right now, it seems that rust works similar to C++ in this regard, meaning that there is no hint at the call site that a parameter may or may not be modified by the function. In the snippet below, if I'm reading foo() in main.rs and I wonder which lines in foo() could possibly change the value of i, then I have to open up 4 additional files and find the relevant source locations to double check which functions might mutate their arguments. Why isn't it a good idea to require some parameter prefix like mut at the call site so that when I read main.rs I immediately will know which lines among the calls to funcA()..funcD() that might change the value of i ? // ---[ funcA.rs ]--- fn funcA(i: int) - int{ return 2**i; } // ---[ funcB.rs ]--- fn funcB(i: mut int) - int { *i += 1; return 0; } // ---[ funcC.rs ]--- fn funcC(i: int) - int { return 3**i; } // ---[ funcD.rs ]--- fn funcD(i: int) - int{ return 2**i; } // ---[ main.rs ]--- fn foo(i: mut int) { *i += 1; funcA(i); funcB(i); // no mut! funcC(i); funcD(i); } fn main() { let mut i: int = 0; foo(mut i); println!({}, i); } Martin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
There is no real answer beyond the one I already gave: that we are already precisely as explicit as C, that Rust references do not actually have the hidden mutation hazard of C++ references, and that changing would place the language in a different space entirely. Please don't suggest that I am (or that anyone else on the list is) being dishonest. Patrick Vadim vadi...@gmail.com wrote: I think the real answer is at this point nobody wants to tweak basic Rust syntax yet again. See the other thread about Rust roadmap, etc. Oh well... On Wed, Jan 1, 2014 at 3:49 PM, Martin Olsson mar...@minimum.se wrote: Short version of my question: Why doesn't rust require mut param prefix at call sites? i.e. to avoid non-const ref badness that C++ has? Longer version of my question: Since this question was asked recently by vadim and not really answered clearly (imo), I'm also including this longer verbose version of my question. For example in C the call f(a,b); might modify b but not a so the token acts as a call site heads-up flag when reading the code. In C# the out/ref keywords are mandatory at the call site if the callee uses them in its param declaration so there you also get a little in hint when reading the code near the call site. C++ of course has non-const references so f(a,b); might modify both a and b so the hint is missing and I really have to look up the code for f() to be sure. If some function foo() passes a to a bunch of functions then I have to find each such function and check if a can be modified or not, so potentially I have to open a bunch of files and read code there before I can fully understand the code near the call sites. Because of this many large C++ projects have coding styles that disallow non-const refs. See for example the google C++ coding style guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone= Reference_Arguments#Reference_Arguments Right now, it seems that rust works similar to C++ in this regard, meaning that there is no hint at the call site that a parameter may or may not be modified by the function. In the snippet below, if I'm reading foo() in main.rs and I wonder which lines in foo() could possibly change the value of i, then I have to open up 4 additional files and find the relevant source locations to double check which functions might mutate their arguments. Why isn't it a good idea to require some parameter prefix like mut at the call site so that when I read main.rs I immediately will know which lines among the calls to funcA()..funcD() that might change the value of i ? // ---[ funcA.rs ]--- fn funcA(i: int) - int{ return 2**i; } // ---[ funcB.rs ]--- fn funcB(i: mut int) - int { *i += 1; return 0; } // ---[ funcC.rs ]--- fn funcC(i: int) - int { return 3**i; } // ---[ funcD.rs ]--- fn funcD(i: int) - int{ return 2**i; } // ---[ main.rs ]--- fn foo(i: mut int) { *i += 1; funcA(i); funcB(i); // no mut! funcC(i); funcD(i); } fn main() { let mut i: int = 0; foo(mut i); println!({}, i); } Martin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev -- Sent from my Android phone with K-9 Mail. Please excuse my brevity.___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
I could be pretty wrong, so if I am, I apologize and please ignore. Anyway, I thought I once read somewhere that when you call a function defined like: fn foo(a: mut int) { ... } with code that looks like fn bar(b: mut int) { foo(b); } that despite what it looks like, you aren't really passing the value b into the function foo(). My understanding, is that when you pass a reference to foo(), that it takes ownership of that reference making it inaccessible to any following code. Since this is generally not what anyone wants, Rust silently re-borrows b and passes that re-borrowed version of the reference to foo() which takes ownership of it. Since b wasn't actually passed to foo(), code after the call to foo() can continue to use b since bar() still owns b. Anyway, if that is all correct, and I'm not sure how likely that is all to be correct, it feels like what this email thread really boils down to is a proposal to eliminate automatic re-borrowing of a mut to mut when invoking a function. I'm may be wrong, but, I'm also under the impression that manually re-borrowing would look something like: foo(mut (*b)) which is extremely unpleasant, so, I'd imagine that the 2nd part of the proposal is to make some sort of nicer syntax for that. To me, this doesn't sound as much like a proposal for a change in syntax as a proposal to remove a bit of magic that Rust is currently doing. I don't know that I'm necessarily in favor or that though, since it would certainly make code more wordy. That wordiness might be nice, however, if it makes it clearer where variables might be mutated (eg: imagine that foo() is originally defined to take a ,so bar() assumed that the variable won't be mutated. However foo() is later redefined to take a mut which silently breaks bar()'s assumption about foo()). -Palmer Cox On Wed, Jan 1, 2014 at 11:41 PM, Vadim vadi...@gmail.com wrote: I think the real answer is at this point nobody wants to tweak basic Rust syntax yet again. See the other thread about Rust roadmap, etc. Oh well... On Wed, Jan 1, 2014 at 3:49 PM, Martin Olsson mar...@minimum.se wrote: Short version of my question: Why doesn't rust require mut param prefix at call sites? i.e. to avoid non-const ref badness that C++ has? Longer version of my question: Since this question was asked recently by vadim and not really answered clearly (imo), I'm also including this longer verbose version of my question. For example in C the call f(a,b); might modify b but not a so the token acts as a call site heads-up flag when reading the code. In C# the out/ref keywords are mandatory at the call site if the callee uses them in its param declaration so there you also get a little in hint when reading the code near the call site. C++ of course has non-const references so f(a,b); might modify both a and b so the hint is missing and I really have to look up the code for f() to be sure. If some function foo() passes a to a bunch of functions then I have to find each such function and check if a can be modified or not, so potentially I have to open a bunch of files and read code there before I can fully understand the code near the call sites. Because of this many large C++ projects have coding styles that disallow non-const refs. See for example the google C++ coding style guide: http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml?showone= Reference_Arguments#Reference_Arguments Right now, it seems that rust works similar to C++ in this regard, meaning that there is no hint at the call site that a parameter may or may not be modified by the function. In the snippet below, if I'm reading foo() in main.rs and I wonder which lines in foo() could possibly change the value of i, then I have to open up 4 additional files and find the relevant source locations to double check which functions might mutate their arguments. Why isn't it a good idea to require some parameter prefix like mut at the call site so that when I read main.rs I immediately will know which lines among the calls to funcA()..funcD() that might change the value of i ? // ---[ funcA.rs ]--- fn funcA(i: int) - int{ return 2**i; } // ---[ funcB.rs ]--- fn funcB(i: mut int) - int { *i += 1; return 0; } // ---[ funcC.rs ]--- fn funcC(i: int) - int { return 3**i; } // ---[ funcD.rs ]--- fn funcD(i: int) - int{ return 2**i; } // ---[ main.rs ]--- fn foo(i: mut int) { *i += 1; funcA(i); funcB(i); // no mut! funcC(i); funcD(i); } fn main() { let mut i: int = 0; foo(mut i); println!({}, i); } Martin ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev ___ Rust-dev mailing list
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On 1/1/14 9:13 PM, Palmer Cox wrote: To me, this doesn't sound as much like a proposal for a change in syntax as a proposal to remove a bit of magic that Rust is currently doing. I don't know that I'm necessarily in favor or that though, since it would certainly make code more wordy. That wordiness might be nice, however, if it makes it clearer where variables might be mutated (eg: imagine that foo() is originally defined to take a ,so bar() assumed that the variable won't be mutated. However foo() is later redefined to take a mut which silently breaks bar()'s assumption about foo()). That's a much more interesting question. I do worry about the verbosity though, as you said. In general I feel like we should either have autoborrowing in as many places as reasonably possible or autoborrowing nowhere. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On Wed, Jan 1, 2014 at 9:12 PM, Patrick Walton pwal...@mozilla.com wrote: There is no real answer beyond the one I already gave: that we are already precisely as explicit as C, that Rust references do not actually have the hidden mutation hazard of C++ references, and that changing would place the language in a different space entirely. Patrick, I disagree with this point. Rust references *do* have hidden mutation hazard, as do C's and C++'s pointers. In all three, mutation hazard is only obvious when you take an address of a stack variable. After that, when you already have a pointer, you pass it around, and never know who might mutate the underlying object. And let's not forget about the heap-allocated objects, which start out as pointers in the first place. Well, since requiring '' at the original borrow site doesn't really prevent the unexpected mutability problem, why not drop it and eliminate a bunch of noise from Rust sources? And, again, if unexpected mutability is what concerns people, mut annotation is the better way to fix that, IMHO. Please don't suggest that I am (or that anyone else on the list is) being dishonest. My apologies, I didn't mean to imply that. Vadim ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On 1/1/14 10:06 PM, Vadim wrote: Well, since requiring '' at the original borrow site doesn't really prevent the unexpected mutability problem, why not drop it and eliminate a bunch of noise from Rust sources? But it does eliminate mutation of lvalues. And, again, if unexpected mutability is what concerns people, mut annotation is the better way to fix that, IMHO. I don't know if it's a coherent proposal. Consider these four function signatures, each of which might mutate their arguments: fn f(x: mut int) { ... } fn g(x: (mut int, mut int)) { ... } struct S'a { a: 'a mut int, b: 'a mut uint, } fn h(x: S) { ... } fn iT(x: T, f: |T|) { f(x) } How might `i` mutate its argument? Consider function `j`: fn j() { let mut x = 3; i(mut x, |ptr| *ptr = 5); } So `i` mutated its argument. So how should you be forced to notate that? Should you have to write: fn iT(x: T, f: |T|) { f(mut x) } ... i(mut x, |ptr| *ptr = 5); Or: fn iT(x: T, f: |T|) { f(x) } ... i(mut mut x, |ptr| *ptr = 5); Or: fn iT(x: T, f: |T|) { f(mut x) } ... i(mut mut x, |ptr| *ptr = 5); And that's just a simple example: start throwing in existential types like traits and it becomes clear that you really can't tell from the program where mutation could possibly happen, because the types are hiding mutability from you. And that's fine--existential types and generics deliberately permit that abstraction. But it does mean, I think, that we can't meaningfully talk about a sound and complete mut annotation at call sites. Patrick ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev
Re: [rust-dev] Why doesn't rust require mut param prefix at call site?
On Thu, Jan 2, 2014 at 1:06 AM, Vadim vadi...@gmail.com wrote: And let's not forget about the heap-allocated objects, which start out as pointers in the first place. Unique pointers have value semantics so this shouldn't be relevant to the visibility of mutation. The consensus is already to remove the auto-coercion of `~T` to `mut T` because it doesn't make any sense. The auto-coercion to `T` will probably either be removed or extended to `T` too, but that hasn't been decided (or discussed much). ___ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev