Returned value of assignment in Julia

By: Mosè Giordano

Re-posted from: https://giordano.github.io/blog/2017-12-02-julia-assignment/

Today I realized by chance that in
the Julia programming language, like in C/C++,
assignment returns the assigned value.

To be more precise, assignment returns the right-hand side of the assignment
expression. This doesn’t appear to be documented in the current (as of December
2017) stable version of the manual, but
a
FAQ has
been added to its development version. Be aware of this subtlety, because you
can get unexpected results if you rely on the type of the returned value of an
assignment:

julia> let a
         a = 3.0
       end
3.0

julia> let a
         a::Int = 3.0
       end
3.0

In both cases the let blocks return 3.0, even though in the former case a
is really 3.0 and in the latter case it’s been marked to be an Int.

Assignment in the REPL

The fact that assignment returns the assigned value is a very handy feature.
First of all, this is probably the reason why in the Julia’s REPL the assigned
value is printed after an assignment, so that you don’t have to type again the
name of the variable to view its value:

julia> x = sin(2.58) ^ 2 + cos(2.58) ^ 2
1.0

Instead in Python, for example, assignment returns None. Thus, in the
interactive mode of the interpreter you have to type again the name of the
variable to check its value:

>>> from math import *
>>> x = sin(2.58) ** 2 + cos(2.58) ** 2
>>> x
1.0

Using assignment as condition

Another useful consequence of this feature is that you can use assignment as
condition in, e.g., if and while, making them more concise. For example,
consider this brute-force method to compute
the Euler’s number
stopping when the desired precision is reached:

euler = 0.0
i = 0
while true
    tmp = inv(factorial(i))
    euler += tmp
    tmp < eps(euler) && break
    i += 1
end

By using this feature the while can be simplified to:

euler = 0.0
i = 0
while (tmp = inv(factorial(i))) >= eps(euler)
    euler += tmp
    i += 1
end

Can this feature be a problem in Julia?

A common objection against having this feature in Python is that it is
error-prone. Quoting from
a Python tutorial:

Note that in Python, unlike C, assignment cannot occur inside expressions. C
programmers may grumble about this, but it avoids a common class of problems
encountered in C programs: typing = in an expression when == was intended.

This is indeed an issue because in C and Python conditions can be pretty much
anything that can be converted to plain-bit 0 and 1, including, e.g.,
characters. In addition, in Python a variable can freely change the type, so
that

Consider the following C program:

#include <stdio.h>

int main()
{
  char a = '\0';

  if (a = 0)
    printf("True\n");
  else
    printf("False\n");

  if (a == 0)
    printf("True\n");
  else
    printf("False\n");

  return 0;
}

which prints

False
True

Mistyping the condition (= instead of == or vice-versa) in this language can
lead to unexpected results.

Instead, this is mostly a non-issue in Julia because conditions can only be
instances of Bool type. One way to make an error in Julia is the following:

julia> a = false
false

julia> if (a = false)
           println("True")
       else
           println("False")
       end
False

julia> if a == false
           println("True")
       else
           println("False")
       end
True

but it is kind of useless to test equality with a Bool as a condition, since
you can use the Bool itself. The only other possible error you can make in
Julia I came up with is the following:

julia> a = false
false

julia> b = false
false

julia> if (a = b)
           println("True")
       else
           println("False")
       end
False

julia> if a == b
           println("True")
       else
           println("False")
       end
True

For this case I don’t have an easy replacement that could prevent you from an
error, but this is also an unlikely situation. The Julia style guide suggests
to
not parenthesize conditions.
Following this recommendation is a good way to catch the error in this case
because the assignment requires parens:

julia> if a = b
           println("True")
       else
           println("False")
       end

ERROR: syntax: unexpected "="