It seems the latter is more common than the former, and that would avoid to have to add "&" everywhere.
It seems the latter is more common than the former, and that would avoid to have to add "&" everywhere.
Currently the types are:
owned T T
ref of T &T
ref of ref of T &&T
You're suggesting that instead you skip the "&" and write some sigil for owned types, say "@": owned T @T
ref of T T
ref of ref of T ???
How do you write the type "ref of ref of T"?On its own this isn't a super compelling argument, because "&&T" is an unusual type that one doesn't normally use. But it hints at the fact that "&" is a modifier. The stronger but less pithy version of this argument is that if you have a type parameter "T" it's essential that it can be instantiated as "T=&U" for some "U".
EDIT: come to think of it, you don't often write "&&T", but it is commonly used. If you `println!("{}", x)` where "x" is a reference, the "println!" macro also takes a reference and you get a "&&" type.
Yup, i see them all the time in iterators too. Eg `foos.iter().filter(|t| ..` `t` is `&&Foo` in that example, iirc. Not that you usually see it though, due to closures obscuring types.
I have to assume rust creators knew what they were doing since they are obviously way more experienced at this than me, but I still don't get it.
- Does "i32" mean an integer or a reference to an integer? You almost always want it to be an integer, so maybe we carve out an exception for small primitive types, that they don't get an implicit "&".
- Likewise some library-defined types like "Rc<T>". "Rc<T>" is the way you store a ref-counted T. So you usually want "Rc<T>" instead of "&Rc<T>". Is there an exception for this type, too, or do you always have to write "@Rc<T>"? It's defined in the standard library, so if it gets an exception than there has to be a language mechanism for "types that should not have an implicit &".
- The ".next()" method on iterators has the type signature "next(&mut self) -> Option<T>", where "T" is the type of the iterator's elements. Under your proposal, you'd write "next(&mut self) -> Option<@T>". If "T=&str", then you're returning an "Option<@&str>". Which has to be equal to "Option<&str>" or else everything breaks, but that might not be super intuitive to programmers.
That last one's the most important, though I don't know how to explain it clearly. If you have a type parameter "T", then "T" does not mean owned T. It means "T", whatever "T" is. If "T" is a reference, then it's a reference. And if you have a type parameter "T" then "&T" means a reference to "T" whatever "T" is. If "T" is itself a reference, then "&T" is a reference to a reference.
There's one other thing in Rust that would be kind of difficult if passing a reference were the default, rather than the owned value. Rust has implicit returns so the last thing at the end of a block or function is returned. If you needed to explicitly ask for ownership, you'd need to do that at the end of every function. Also, Rust will yell at you if you try to have a function return a reference to a value that's going to be dropped.
In C++, I think that the use of '&' came from the use of '&' in C as meaning "the address of". A reference and an address to a value are similar concepts.
It was tedious and eventually dropped. For example, it's more natural to move in assignment. `= move` is weirdly boilerplatey, `=` borrowing is unhelpful, and `=` moving without the move keyword is inconsistent.
Also the moment something is borrowed starts a lifetime scope, which is useful to know. It'd be harder to notice loan scopes of loans were implicit.
f(&s);
is practically equal to let r = s.borrow();
f(r);