# Explicit denotation of variability and immutability

**URL:** <https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686>\
**Category:** Internals & Design\
**Tags:** proposal\
**Created:** [January 30, 2018, 10:16am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686 "2018-01-30T10:16:36Z")\
**Posts on this page:** 20\
**Page:** 2

<div class="post-metadata">

**Author:** ![Liso](https://avatars.discourse-cdn.com/v4/letter/l/898d66/32.png) [@Liso](https://discourse.julialang.org/u/Liso)\
**Post date:** [January 31, 2018, 6:07am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/21 "2018-01-31T06:07:25Z")

</div>

Could you show examples for better understanding this (emphasis are mine)?

> _“Expressions **don’t have** types, only values do, and the type that the **compiler thinks** an expression **has** is just an implementation detail that generally **doesn’t affect the behavior** of code. (There are a few corner cases where we allow type inference to **leak into visible behavior** , but it’s avoided as much as possible.)”_

From your words one could think that language behavior is not well defined. I hope that deeper explanation could diminish this suspicion.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [January 31, 2018, 7:49am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/22 "2018-01-31T07:49:17Z")

</div>

If you want to read more, you can check out this StackOverflow answer:

> <https://stackoverflow.com/questions/28078089/is-julia-dynamically-typed/28096079#28096079>

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 10:26am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/23 "2018-01-31T10:26:11Z")

</div>

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:

```julia
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:

```julia
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`, `Vector`s, `Matrices`, `Dict`s, `Set`s, 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.,

```julia
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.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [January 31, 2018, 10:37am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/24 "2018-01-31T10:37:35Z")

</div>

But who really cares about bindings? You can’t change any data given to you from a caller by changing a binding. This is different to C where you can pass by reference which is not possible in Julia (everything is passed by value).

What is interesting is mutation of data. And for that, in Julia, you would use some immutable data structure or wrapper. It gives the same promise, “you should not really modify this”, but without any guarantees (someone might reach into the wrapper and do bad stuff).

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 11:02am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/25 "2018-01-31T11:02:44Z")

</div>

> who really cares about bindings?

I think a binding, by `=`, _serves a clear purpose_ in a **computational** code; currently, assignment or equality.  
It is important to distinguish between the two – so I do care at least! 😃  
The syntax should be explicit in this respect, I believe. This prevents a lot of human mistakes when you re-writing a mathematical algorithm in code. “You can’t change any data given to you from a caller by changing a binding”, but you might mistakenly change the binding, and hence change the meaning of a “name” which actually represents a mathematical symbol with a certain rôle.

Yet you are right in that “what is interesting is mutation of data”. I don’t see why one should write

```julia
function foo(x, y, z)
    #... do a lot of stuff ...
    x[1] = -1
    #... do a lot of stuff ...
end

```

instead of the explicit way,

```julia
function foo(x::Mutable, y, z)
    #... do a lot of stuff ...
    x[1] = -1
    #... do a lot of stuff ...
end

```

Isn’t reading and reasoning about the explicit version easier for a programmer?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [January 31, 2018, 11:11am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/26 "2018-01-31T11:11:50Z")

</div>

But the absence of a `::Mutable` (or presence of an `::Immutable`) -annotation is only valuable if it is enforced recursively to all calls in the function.

Otherwise you will just have

```julia
f(x) = g(x)
g(x::Mutable) = x[1] = 2

f([1,2,3])

```

which will modify your data even though you called a function that was supposed to have `x` non-mutable.

How do you plan to enforce this in a dynamic language like Julia?

The way to do this is by changing the _object_ you send in, e.g. instead of sending in `[1]` you send in `ImmutableArray([1])`. Objects flow through functions, not variables (bindings) so it is there the const-annotation need to be, i.e. part of the type.

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 11:12am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/27 "2018-01-31T11:12:30Z")

</div>

Thanks for providing an example. Now I see.  
Yet I deem such a code as _bad_ code, especially for computation.  
Reasoning about what it does is not easy. For example, here, one should first learn about the latest Julia’s conventions on function arguments – which might change – and then understand what `f` would do to an immutable type, or even if the code compiles at all.

I strongly prefer **explicitness** as I said.

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 11:23am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/28 "2018-01-31T11:23:43Z")

</div>

It is similar to the example provided by @Elrod above (see also my [reply](https://discourse.julialang.org/t/8686/27)).  
I do not know how to enforce this practically in Julia, yet what I am saying is that such things shall be prevented (or at least warned against) by default. If I promise _not_ to mutate a state in a certain part of the code, I must observe it, and the compiler should be able to warn me if I violate that. Regardless of the programming language or how it would be practically implemented, this is a plausible idea, isn’t it? It provides also more safety – indeed, one could opt for unsafety, if one wishes.

For an _interactive_ session, you might relax some of those strict rules. And remember, eg., that Haskell, a pure functional language, can also be used interactively.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 31, 2018, 11:41am UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/29 "2018-01-31T11:41:59Z")

</div>

> [@SepandMeenu](#):
>
> clarity, explicity, and being less error-prone should be a goal for the design.

There is a trade-off here: extra annotation would also increase visual/semantic clutter. The more boilerplate, the easier it is to lose track of relevant code. Clarity would suffer because of verbosity.

At the end of the day, all of these trade-offs are subjective and based on experience. Accidentally overwriting a variable in local scope happens, but it is no more insidious than other random typos. IMO the price of this semantic change just to catch this would be too high.

Also, I would like to reiterate that suggesting fundamental design changes “before it’s too late” to a language you have not been using very long is perhaps premature. I am not saying that outsiders don’t have valuable perspectives to offer, but it is very hard to resist the temptation to redesign a language just to make up for features that you are missing from another one and you have not yet learned to use the new one idiomatically. Give Julia some time.

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 12:00pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/30 "2018-01-31T12:00:24Z")

</div>

Your stance is quite subjective, I’m afraid. I am not then sure how you’d judge, eg., the following pieces of advice on the official “Julia Performance Tips”:

- Declare types of keyword arguments
- Break functions into multiple definitions
- Write “type-stable” functions
- Avoid changing the type of a variable

Those doubtlessly lead to more verbose code. Shall we avoid them due to the “clutter”?  
Or how do you convince yourself about the default immutability of `struct`s in the current standard?

I am not expecting that Julia be another Haskell. Yet, I believe there is aleady a trend within Julia that can be generalized systematically and allows better computational code.

---

<div class="post-metadata">

**Author:** ![Tamas\_Papp](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tamas_papp/32/25949_2.png) [@Tamas\_Papp](https://discourse.julialang.org/u/Tamas_Papp)\
**Post date:** [January 31, 2018, 12:30pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/31 "2018-01-31T12:30:01Z")

</div>

AFAIK some of these are transient workarounds (may be unnecessary as the compiler improves), while the need for type stability is a fundamental consequence of Julia’s design (but even that was relaxed recently). That said, I never said that my own preferences about clutter were “objective” in any sense.

> [@SepandMeenu](#):
>
> how do you convince yourself about the default immutability of structs in the current standard?

One thing that I would like to emphasize is that I _shouldn’t need to_. It was a design decision carefully hammered out by people who have been developing and using Julia for years. I have been a Julia user for years now, but I still recognize that many discussions, especially about the compiler, are above my head, and I trust that the core developers are making the right choices. I look at the core language primarily as something to use, then as something to learn a lot from; not primarily as something I should redesign, because I lack the expertise and the perspective.

That said, my understanding is that this particular choice is a nice confluence of good practices (avoid mutation unless you have to), compiler optimizations (given an `immutable`, it can make assumptions that it otherwise could not). But again, it was not always the default — it was arrived at after a lot of careful discussion that went on for _months_ (see [#19157](https://github.com/JuliaLang/julia/issues/19157) and the issues linked there), after the language has existed for _years_.

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 12:46pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/32 "2018-01-31T12:46:53Z")

</div>

I agree with you in that default immutability of `struct`s “is a nice confluence of good practices (avoid mutation unless you have to), compiler optimizations (given an immutable, it can make assumptions that it otherwise could not)”, and that “it was arrived at after a lot of careful discussion that went on for months”. So it’s time, imo, to start a serious objective discussion about generalization of that decision; it may take a long while till an agreement is reached, but it is worth it.  
It is interesting that you deem “avoid mutation unless you have to” a _good_ practice; this is what I am pushing for in my proposal, but in a general way. 😃

And remember, code is _not_ written solely for a compiler to crunch, it has also a **human audience** – as I have emphasised in my [reply](https://discourse.julialang.org/t/8686/23) to StefanKarpinski and foobar\_lv2. Compiler technology is beyond my understanding.

I think that sometimes we, “the laypeople”, have to “nudge” the core developers to make the right choices. Otherwise, history shows how things can go askew.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 31, 2018, 1:05pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/33 "2018-01-31T13:05:35Z")

</div>

> [@SepandMeenu](#):
>
> it is an explicit “promise” from the programmer (a human!);

And yet const\_cast exists. I would prefer if C++ allowed the compiler to assume const-ness (making modification of consts UB; possibly having a slow debug-mode that compiles in checks for const-ness, e.g. by most brutally mapping a page as read-only (a factor 1000 slowdown for debug is often acceptable)). I have so often been driven crazy by C++ code that declares something as “const” and then goes on to modify private internal state, making the entire thing crash and burn when I try to run it multithreaded. Formulated more brutally: I see no point at all in C++ const; it belongs in doxygen, not syntax. The compiler cannot assume const-ness of consts, and I as a user of a library can neither.

> [@kristoffer.carlsson](#):
>
> This is different to C where you can pass by reference which is not possible in Julia (everything is passed by value).

Well, to be honest, ``mutable’’ in julia is syntactic sugar for pass-by-reference. It is just that the type system in julia makes a much stronger distinction between mutable/immutable.

And, as I said, a `@const arg` would be nice (say, I pass a vector, where I don’t know the size at compile-time; currently there is no way of promising, both to compiler and readers of the source, that I won’t modify the vector). Note that I am not proposing that julia actually enforces this in default-mode; but I am proposing to make modifications UB, and promise that modification of const-annotated things will stay UB for all future (such that I can write a bug report whenever someone modifies private internal state of `@const` things that prevents multithreading).

Re general discussion by @SepandMeenu

I think one of the most important points to remember is that 1. Julia does not have method types like `f: Int->Int`; 2. Julia does not support binary compatible types (C++ subclasses; C unions); 3. Julia makes no guarantees that different methods of the same function are related in any way.

(2) and (3) go together: Dispatch must go to the actual type, and Julia must always know the actual type; there is no way of globally saying  
`getindex_(x::Vector{T}, idx) where {T} = x[idx]::T`  
because more specific definitions can always violate this property.

As an aside: Unfortunately, the following does currently not work:

```julia
reinterpret(NTuple{8,UInt8}, UInt64(4))
ERROR: bitcast: target type not a leaf primitive type

```

I would very much like a way of getting this to work! (that is: allow reinterpret between arbitrary bitstypes of the same size)

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 1:16pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/34 "2018-01-31T13:16:31Z")

</div>

- On C++ `const` keyword  
Note that I am _not_ defending C++ style – I find that indeed a bad coding practice. Unforunately, the current design of C++ allows many bad coding styles.  
But that does _not_ mean that `const` is just useless. As I said in my proposal one should _not_ cast a Constant/Immutable to a Variable/Mutable in the corresponding scope; or at least, there should be a clear warning.

- I did not understand the following (and its relation to my proposal):

> [@foobar\_lv2](#):
>
> there is no way of globally saying
> 
> ```julia
> getindex_(x::Vector{T}, idx) where {T} = x[idx]::T
> 
> ```
> 
> because more specific definitions can always violate this property.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 31, 2018, 1:28pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/35 "2018-01-31T13:28:51Z")

</div>

> [@SepandMeenu](#):
>
> I did not understand the following (and its relation to my proposal):

Afaik, julia does not attempt to do shortcuts when determining return-types of functions. There is AFAIK no way to express that e.g. a function `f: T -> Tuple{T,T}`; this might hold for some `T` and might not hold for others. Hence, type-stability is not a property of your function (as in `source-code`) but rather a property of the method post specialization on all input types. This severely limits all your attempts at type-stability in your code, (you must rely on all input types behaving sensibly) and makes too verbose annotations moot IMHO.

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [January 31, 2018, 1:41pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/36 "2018-01-31T13:41:22Z")

</div>

> [@foobar\_lv2](#):
>
> Well, to be honest, ``mutable’’ in julia is syntactic sugar for pass-by-reference. It is just that the type system in julia makes a much stronger distinction between mutable/immutable.

No, it is not? Passing by reference means that the variable in the function is the _same one_ as the one outside the function. This is not the case in Julia, everything is passed by value, no difference between mutable and immutable types.

---

<div class="post-metadata">

**Author:** ![foobar\_lv2](https://avatars.discourse-cdn.com/v4/letter/f/ee59a6/32.png) [@foobar\_lv2](https://discourse.julialang.org/u/foobar_lv2)\
**Post date:** [January 31, 2018, 1:47pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/37 "2018-01-31T13:47:46Z")

</div>

Hmm. Maybe I’m confused, but isn’t julia always passing `pointer_from_objref` for mutables (on the ABI level)? So passing a mutable is syntactic sugar for passing a pointer, just as references in C++ are syntactic sugar for C pointers?

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 1:55pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/38 "2018-01-31T13:55:53Z")

</div>

Now I see an interesting discussion between @foobar_lv2 and @kristoffer.carlsson !  
Isn’t it better to be explicit about mutation in code syntax, after all, for the sake of mental sanity of later generations 🙂 ?

---

<div class="post-metadata">

**Author:** ![kristoffer.carlsson](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/kristoffer.carlsson/32/22_2.png) [@kristoffer.carlsson](https://discourse.julialang.org/u/kristoffer.carlsson)\
**Post date:** [January 31, 2018, 2:29pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/39 "2018-01-31T14:29:39Z")

</div>

In Julia:

```julia
mutable struct M
    v::Int
end

x = M(1)
function f(x::M)
    x = M(2)
    return
end
f(x);
print(x)

```

will print `M(1)`.

In C++:

```julia
#include <stdio.h>

void f(int &x) {
    x = 2;
    return;
}

int main() {
    int x = 1;
    f(x);
    printf("%d", x);
    return 0;
}

```

will print `2`.

C++ can pass by reference, Julia by value (always).

---

<div class="post-metadata">

**Author:** ![SepandMeenu](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sepandmeenu/32/8846_2.png) [@SepandMeenu](https://discourse.julialang.org/u/SepandMeenu)\
**Post date:** [January 31, 2018, 2:32pm UTC](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686/40 "2018-01-31T14:32:54Z")

</div>

what about this?

```julia
mutable struct M
    v::Int
end

x = M(1)

function f(x::M)
    x.v += 1
    return
end

f(x);
print(x) # prints M(2)

```

In my proposal, this version of `f` will produce an error/warning, since `x` is assumed to be _immutable_ in the function arguments, unless stated _explicitly_, e.g., via `function f(x::mut M)` or `function(mut x::M)`.

In your example, `x = M(2)` is a new _binding_ for a local `x` inside the function scope, afaiu. It does not tell whether the `M`-instance is passed by reference or value.

[Previous page](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686.md?page=1)

[Next page](https://discourse.julialang.org/t/explicit-denotation-of-variability-and-immutability/8686.md?page=3)
