Let me first emphasise that I mean no radical change to the fundamental structure, type system, or the logic of Julia – it is already a lovely “progressive” language. My proposal is meant towards a more readable and safer syntax for translating computational algorithms into Julia. How it would be implemented under the hood is a matter for core developers and the more knowledgeable part of the community – I am no computer scientist, but coming from the math realm.
- Most succinctly, what I propose is certain explicit syntactical safeguards to denote mutation of values and bindings (mutations of the state). I firmly believe that it leads to much better coding style in the long run, especially benefits concurrent/parallel programming.
For example, according to the proposal, by
a = 2
b = Array{Int32}(10)
c = ImmutableArray{Int32)(5, 5)
the programmer and the code reader (plus the compiler) will be sure that a
is an immutable binding to the value 2, b
is an immutable binding to a mutable Array
, and c
is an immutable binding to an immutable Array
. If, somewhere else in the code, such decisions/pledges are violated, the compiler will throw an error or a warning.
Mutability will be then explicitly marked up, as in
v::Integer := 2
w := -1.5
z.c0 := f
z[i] := 32a + h(2)
where everybody (along with the compiler) is informed that v
is intended to be a mutable binding (but with immutable type) to a value 2, w
is a mutable binding (with mutable type) to a value, -1.5, and z.c0
and z[i]
values are intentionally mutated.
Using :=
for mutation and =
for constant binding (in the corresponding global or local scopes) does not hurt any fundamental principle of Julia, or a quick-scripting user of the interactive mode. In fact, it promotes better coding style which is also closer to the mathematical syntax and much safer (since the compiler knows the intent of the programmer and can warn her if needed).
- For further safety inside function bodies and easier reasoning about the code, I see a strong need for an explicit syntactical mechanism like the
intent
keyword of FORTRAN (see above); for instance, by a construction like
# a pure function
function fp(a::Int64, s::Set{Int32})
#... do some computation ...
end
the programmer explicitly promises not to mutate the bindings of the arguments or their contents in the function body, so that
a = 2
a := -1
push!(s, 9)
s = Set([1, 2])
s := s2
will produce compiler errors.
In contrast, a definition like
# an impure function
function fip(var a::Int64, mut s::Set{Int32})
#... do some computation ...
end
allows
a := 2
a += 1
push!(s, 9)
a = 2 # `a` becomes constantly bound thereafter
where var
and mut
are “flags” to show explicitly that the programmer intends to mutate the binding/value of a
and mutate the contents of s
with this function.
This is also not against any fundamental principles of Julia, afaiu, but leads instead to much safer codes, which are very easy to reason about by a human.
[Note: I am not insisting on this particular notation; better notation could be devised for this purpose.]
- I think there is a need for an in-built mechanism to map mutable types to immutable types automatically; e.g., suppose that somebody has built up a library which includes a mutable type
List
with a push
method to append elements to the List
. Then something like
typealias ImmutableList Immutable(List)
will generate an immutable-List
type which can only be initialized; moreover, any mutation method built for List
will produce an error when applied to ImmutableList
; e.g., after the generation of the immutable type above, and defining
lm = List([1, 2, 3])
lim_1 = ImmutableList([5, 6, 7])
lim_2 = ImmutableList(lm) # an immutable copy of `lm`
either of
push!(lim_1, 8)
push!(lim_2, 4)
will produce a compile error, while
push!(lm, 4) # does not mutate `lim_2`
works fine.
This is the only radical part of my proposal, if at all. I am not sure how this could be implemented in Julia or if this violates Julia’s foundations. Yet, that seems to be quite a useful mapping.
Implicit mutation is the “dangling pointer” of modern languages.