Explicit denotation of variability and immutability

Thanks for the detailed reply, @StefanKarpinski.
My proposal has admittedly shortcomings of different sort, but I felt a need for such a discussion when Julia is still in its infancy. So, I hope more critique/support/improvements will appear.

I understand your explanation of dynamic and static types in C++, but here I am mostly interested in the clarity of syntax – not optimisations which would aid the compiler (as @foobar_lv2 might prefer).
Computational code is written and read by humans (not just machines), so clarity, explicity, and being less error-prone should be a goal for the design.

Let’s make an example; consider the following C/C++ snippet:

int foo(const int n, const* const int x, double y)
{
    //... do stuff ...
    return 0;
}

In this function definition, using const modifiers is not just a means for producing optimised machine code; it is an explicit “promise” from the programmer (a human!); in words, it says:

The programmer promises that she will not reassign n or x, and will respect the immutability of x in this part of the code.

Such a syntax will doubtlessly facilitate reasoning about the code for a second programmer who wants to read the code for understanding or debugging it.
Another example from FORTRAN, explicit declaration of pure functions:

pure function square(x)
  real, intent(in) :: x
  real :: square
  square = x * x
end function

In this snippet, it is easy for a compiler to determine the purity of a function, but it adds explicit “promises” from the programmer, which can be verified thoroughly by a compiler.

Such explicitness, imo, reduces a lot of human mistakes in code, while promoting better coding styles (esp., being easy to read and reason about) – hence, I disagree with StefanKarpinski’s statement that “local immutability doesn’t really buy you much”.

I do not see why we shouldn’t have such explicitness in Julia which is meant mainly for modern computational tasks. Julia has already made a decision to make user-defined types immutable by default, and to introduce an explicit keyword (mutable) when mutability is required. As StefanKarpinski mentioned, Julia has also Immutable Arrays – honestly, I do not understand the conceptual difference between a Tuple and an Immutable Array, and how Immutable Array fits into the type hierarchy (regarding StefanKarpinski’s statement, “a value can be mutated or not is a property of its type and that type cannot change…”).

I think, one can systematically generalize the aforementioned schemes to all types, for instance, by a “mutation” of my proposal:

  • Aggregate types – meaning the types which you can add or remove elements – like Arrays, Vectors, Matrices, Dicts, Sets, Graphs, Lists, etc., are mutable by default, but one can “wrap [them] in an immutable wrapper” (as StefanKarpinski mentioned) to use them as immutables in some restricted scope (eg., in the body of a function); e.g.,
x = Array{Int64}(10)   # constant binding to a mutable Array
xm = Immutable(x)      # constant binding to an immutable view of x
  • Non-aggregate types or user-defined types will be immutable by default (as the current standard for struct).

I still believe that one should keep a clear distinction between equality and assignment to markup modifications to the state:
As in part (1) of my proposal, use var and <- (or :=) when dealing with (re-)assignments or modifying mutables, and reserve the equality operator (=) for a constant binding.

The function signature should be also explicit in this regard, as I proposed in my original post.