Implicit copy operations from storage to memory, from calldata to memory, from memory to external function arguments, etc is not possible anymore except for value types.
To make an ordinary value copyable, use the copyof operator: x cannot be copied, but copyof x can be copied. Using copyof twice is invalid. Storing a copyable type somewhere erases the copyable property again, i.e. uint[] memory x = copyof y; c.f(x); is invalid.
Would a unitary symbol against the variable be better to indicate assignment by reference rather than introduce a new assignment symbol?
uint[] a;
uint[] b;
function foo() {
uint[] ref = @a; // by reference
b = ref; // elementwise
}
I think something like a = b (a and b are identical afterwards, i.e. assignment by reference) and a <- b (a now holds a copy of b and they are only equal, but might diverge) would be more intuitive. On the other hand, this would require us to change = to <- for value types everywhere.
The @-notation on the other hand, is also useful in places where a copy is performed, but not due to an assignment but e.g. due to passing arguments to a function call.
This is also a question when passing variables of differing location as function arguments (as this came up on yesterday's weekly call).
Instead of considering C++'s *_cast methods I propose to use copy:
contract C{
struct A {}
A a;
function f(A memory a) {}
function g() {
f(copy<memory>(a));
}
}
I would like to open the discussion on this again. As mentioned earlier, an different assignment symbol is not sufficient, because we also need to consider passing data along function calls.
My proposal would be that reference types are always assigned and passed by reference by default. If this is not possible (because it is an assignment to storage or from storage to memory or across function calls), an rvalue can be turned into an rvalue of "copyable type" by using copy(...). The actual copy will only be performed with the assignment or external function call itself, i.e. copy(x) is not yet a copy of x. The type of copy(x) does not allow any member access or operators. copy(copy(x)) is invalid. Assigning a copyable type to a local variable of storage reference type is invalid.
This will result in rather verbose syntax for external function calls. An alternative would be to use a symbol instead of an actual function call (i.e. %x or whatever).
Another alternative would be to perform copies by default and make references explicit. I think this is not as good because it could result in too many unnecessary (and unnoticed) copy operations.
I think always passing by reference by default and requiring a copy(...) construct is good - the only question is whether the resulting verbosity for external function calls is in fact a problem. I think it would probably be fine and using a symbol instead will probably increase the learning curve of the language and decrease its readability (and we could still add a symbol as an alias for copy(...) later, if people complain).
In theory the verbosity could be decreased by just having copy be the identity/no-op for all simple types and allowing to pass function arguments as tuples and having a variadic variant of copy, e.g. a.someFunction(copy(someArray,10,someOtherArray)) being the same as a.someFunction(copy(someArray),copy(10),copy(someOtherArray)) being the same as a.someFunction(copy(someArray),10,copy(someOtherArray)), but that would be a lot at once and probably overkill for the problem at hand (are there plans for allowing to forward tuple-returns as function arguments?)...
I agree with @ekpyron
What about value types? They are copied all the time, so I would assume that a copy operator is not required.
We might also think about using a copy operator instead of a function: f(copy x, copy y[2]). or copyof x.
Note that with this, the expression a = copyof b actually reads like proper english.
These days I'm most in favour of using an operator called copyof.
Open question: Do we also require copyof for things like abi.encode? I would probably say yes.
@axic was suggesting copyof(x) but also said that he is not sold on any of the syntax.
If we use the operator without parentheses, the precedence has to be determined.
Next step would be to take a look at some contracts and see how they would look like.