Assignment Notation
What should the assignment and definition operators be? Odersky started a
discussion about switching to :=
for assignments in
Scala: Use :=
for Assignment. A video by Context Free discusses
this: Demo
Zoo: Assignment, Vars, & Consts.
Assignment Operations
There are basically these operations
- Assignment to a variable, in Java
a = b;
- Declaration of a new variable, in Java
type a = b;
- Declaration of a new variable with type inference, in Java
var a = b;
- Comparison of two values, in Java
a == b
- Declaration of a routine with result type inference, in Fuzion so far
a => b
Considerations
Mathematical Notation
Using =
for an assignment is mathematically very unsatisfactory,
code such as x = x + 1
mathematically does not make sense.
Discourage Mutation
Assignments are mutations of a variable and should be avoided, declarations should be preferred whenever possible.
left-to-right execution order
Assignments and declarations are the wrong way around.
sum := a + b + c
A notation that puts the variable at the end represents the flow of execution better.
a + b + c =: sum
Assignments for Control Flow
A common reason for assignments are values depending on control flow.
next i32 if x < 999 next = x + 1 else next = 0 tail_call(next) -- some use of next
One way to avoid this is allowing statement results that can be used in declarations
next := if x < 999 x + 1 else 0 tail_call(next)
or maybe using the left-to-right order
if x < 999 x + 1 else 0 =: next tail_call(next)
Assignment as Expression with Result
Having assignments produce a result is an awful idea from a functional perspective. An assignment as part of an expression introduces a side-effect. Even if only used as a declaration of a new variable, this variable can be hidden deep in an expression and together with lazy operations, it additionally results in complex visibility rules.
The most convincing example in the big discussion about Python 3.8's walrus operator that I have seen is this loop
# Python code: chunk = file.read(8192) while chunk: process(chunk) chunk = file.read(8192)
Which can be simplified to
# Python code: while chunk := file.read(8192): process(chunk)
For Fuzion, the powerful loop syntax instead should allow
for chunk := file.read(8192) while chunk? process(chunk)
which avoids the second call to file.read
. Disregarding the
braces, the code essentially adds chunk
once, which is so little
additional typing that it does not justify the complexity of having assignments
as expressions.
Future Fuzion Proposal
- Assignment:
set v := expr
, whereset
indicates to set an existing field. Alternativelyexpr =: set v
- Declaring a new field:
v type := expr
orexpr =: v type
. - Declaring a new field with type inference:
v := expr
orexpr =: v
. - Comparison of two values:
a = b
- Declaration of a routine with result type inference:
a => b
Open Questions
Will the set
keyword in an assignment make the definition more popular?
Are the left-to-right versions too confusing or could they turn out to be useful once one got used to this syntax?
So far, a field is immutable if there is no assignment to it except for the
initial assignment. Together with the fact that assignments are not allowed
outside of the feature that declares the field, the compiler can easily
distinguish mutable from immutable fields. However, do we need better syntax to
make this obvious for the human eye, e.g., requiring a keyword such
as var
in the declaration such that we get var x i32 :=
0
to declare a mutable field x
?
Python, Scala
The assignment operator causes big emotional discussions. Odersky had to step
back, Guido van Rossum gave up his position as BDFL for Python when the walrus
operator :=
was introduced.