modularml / mojo

The Mojo Programming Language
https://docs.modular.com/mojo/manual/
Other
23.26k stars 2.59k forks source link

[Docs] Assignment operator incorrectly described as signalling a copy #1673

Open nmsmith opened 9 months ago

nmsmith commented 9 months ago

Where is the problem?

https://docs.modular.com/mojo/manual/lifecycle/life.html#copy-constructor

What can we do better?

The docs say:

When Mojo encounters an assignment operator (=), it tries to make a copy of the right-side value by calling upon that type’s copy constructor.

This is not true. None of the following assignment statements result in the RHS being copied:

var x = String("foo")  # RHS is an RValue, so it won't be copied. The constructor writes into `x`'s memory.
x = String("bar")      # Same is true when reassigning an existing variable.
var y = x^             # Here, `x` is an LValue, but its value is being moved/transferred instead of copied.

To the best of my knowledge, an assignment operation only implies a copy when the RHS is an LValue expression and the transfer operator is not used.

I should also mention: it wouldn't be accurate to claim that in the general case of x = <some function call>, the default behaviour is to copy, with move/transfer being an optimization. This probably won't be true in the near future, because we want to offer NRVO (#1458) for functions, in which case no move/transfer is performed either. (NRVO allows the specification of functions that directly initialize the memory of a non-movable type.)

jymchng commented 7 months ago

Mojo should allow developers to run custom assignment operator.

forFudan commented 5 months ago

I think it is more about how to narrate in a more beginner-friendly way. A beginner does not need to know that the first two lines are optimized by compiler via moving the values, instead of copying the values, because String("foo") and String("bar") do not appear later.

The third line is a move as there is a ^ after the x. This rule is already in the documentation.

Thus, I think the following sentence is okay, in the sense that it does not throw too much extra information to beginners.

When Mojo encounters an assignment operator (=), it tries to make a copy of the right-side value by calling upon that type’s copy constructor.

nmsmith commented 5 months ago

The bigger issue is that Mojo doesn’t actually have an assignment operator. It has function calls, and = signals where the result of a function call will be stored. When you write y = foo(x), you are only invoking one function call: foo. When you write y = x, you are invoking the __copyinit__ function. When you write y = x^, you are (typically) invoking the __moveinit__ function. There is no operation associated with the = symbol in particular.

forFudan commented 5 months ago

The bigger issue is that Mojo doesn’t actually have an assignment operator. It has function calls, and = signals where the result of a function call will be stored. When you write y = foo(x), you are only invoking one function call: foo. When you write y = x, you are invoking the __copyinit__ function. When you write y = x^, you are (typically) invoking the __moveinit__ function. There is no operation associated with the = symbol in particular.

Yes, indeed. But we also care about how much a beginner can take. "Trying to copy" can already mean that in most cases it is "copyinit" and in some special cases, as in the example you raised above, it is instead "moveinit".

Maybe the best solution is that the documentation makes a footnote for more explanation on this.