The problem: Accessor functions always have to copy their return value, so you can't efficiently get at the content of data structures (except by duplicating the logic needed to access them).
The original solution proposed was to pass the accessor a block and pass the value to that block by reference. This would cause blocks to spring up everywhere (with all the indentation and noise that comes with it) and be extremely un-composable. A while ago I wrote a message to this list proposing a system whereby functions could return references. This week, I've finally implemented that. The exact syntax and semantics are not yet set in stone, so if you see room for improvement, reply. Feature 1: Let bindings can now bind by reference. let &x = foo.bar; This does not copy the content of foo.bar, but introduces a local that references it. The lifetime of this local can not exceed that of foo (you can't use it after you've overwritten foo). Currently, by-reference locals can not be assigned to at all, and must always be initialized right away (this was a complexity tradeoff -- assignment which replaces the contents of the referred-to value could be implemented). You can put destructuring patterns after 'let &', but you can't mix by-copy and by-reference bindings in a single destructuring pattern. Feature 2: Return-by-reference. fn get<T>(o: option::t<T>) -> &T Putting an ampersand in front of the return value of a function indicates that the function returns a reference pointing into one of its arguments. Alias analysis will base the lifetime of the returned reference on the lifetime of the argument. It'll also verify, inside the reference-returning-function, that the returning happens in a safe way. You can then do things like this: let x = get(foo).bar; // Access the reference directly. let &y = get(foo); // Or store it in a by-reference argument let z = get(foo); // This will cause the referred-to value to be copied, so you don't need two variants of accessors If your function takes more than one argument, you have to specify which argument you are referencing by providing a number after the & fn elt<T>(v: [T], n: uint) -> &1 T This is 1-based, 0 is reserved for later use. The above assumes the referenced value is immutably rooted in the argument (the argument is not mutable in a way that might overwrite the reference). When this is not the case, you have to annotate it with an ! fn current_val(c: cell) -> &!content This will make the resulting reference somewhat less convenient to use -- as soon as the value of anything that might alias it (currently by simple type-based alias analysis), it is invalidated, since that might result in the value being overwritten. Still, for careful use, or for immediate consumption, such aliases are much more efficient than making a copy. One major unimplemented part is returning references to the content of objs (this is what &0 is reserved for). The opaque nature of object types makes this somewhat more tricky to check, but I think I've worked out a reasonably convenient way to do it. When I have that, I'll be able to make map.get and map.find return aliases (which was the motivating example for this whole exercise). _______________________________________________ Rust-dev mailing list Rust-dev@mozilla.org https://mail.mozilla.org/listinfo/rust-dev