# Why I can't set what parameters are mutable explicitly?

**URL:** <https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091>\
**Category:** Offtopic\
**Tags:** functions\
**Created:** [August 21, 2022, 3:50pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091 "2022-08-21T15:50:10Z")\
**Posts on this page:** 20\
**Page:** 4

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 22, 2022, 2:04pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/62 "2022-08-22T14:04:39Z")

</div>

> [@aplavin](#):
>
> Enforcing immutability

Closest thing I could think of is `!ismutable(arg) || throw(error("arg must be immutable."))`. Not sure if it’ll help your example, though, that looks like restricting variables again.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 22, 2022, 2:06pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/63 "2022-08-22T14:06:17Z")

</div>

> [@Benny](#):
>
> `!ismutable(arg) || throw(error("arg must be immutable."))`

This runs into the problem that, e.g., `Set` is immutable, while `String` is mutable, even though the observed behaviours are the opposite.

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 2:06pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/64 "2022-08-22T14:06:59Z")

</div>

I correct it.

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [August 22, 2022, 2:54pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/66 "2022-08-22T14:54:37Z")

</div>

> [@Dan\_Micsa](#):
>
> Objects with mutable fields are not protected.

It’s possible to protect the fields of a mutable struct via similar technique. Here’s a prototype.

```julia
import Base: propertynames, getproperty, setproperty!

struct ReadOnlyStruct{T}
    parent::T
end
const ROS = ReadOnlyStruct
propertynames(ros::ROS{T}) where T = propertynames(getfield(ros, :parent))
getproperty(ros::ROS{T}, name::Symbol) where T = getproperty(getfield(ros, :parent), name)
setproperty!(ros::ROS, name::Symbol, x) = error("Cannot set property of ReadOnlyStruct")

mutable struct Foo
    x::Int
end
f!(a::Foo, b::ROS{Foo}) = a.x = 3
g!(a::Foo, b::ROS{Foo}) = b.x = 3 # violates read only contract

```

Demonstration:

```julia
julia> foo = Foo(5)
Foo(5)

julia> bar = Foo(6)
Foo(6)

julia> foo.x = 3
3

julia> foo
Foo(3)

julia> f!(foo, bar |> ROS)
3

julia> g!(foo, bar |> ROS)
ERROR: Cannot set property of ReadOnlyStruct
Stacktrace:
 [1] error(s::String)
   @ Base ./error.jl:33
 [2] setproperty!(ros::ReadOnlyStruct{Foo}, name::Symbol, x::Int64)
   @ Main ./REPL[9]:1
 [3] g!(a::Foo, b::ReadOnlyStruct{Foo})
   @ Main ./REPL[23]:1

julia> propertynames(foo)
(:x,)

julia> propertynames(foo_ro)
(:x,)

julia> hasproperty(foo, :x)
true

julia> hasproperty(foo_ro, :x)
true

```

For convenience only, one could then also define

```julia
f!(a::Foo, b::Foo) = f!(a, ROS(b))
g!(a::Foo, b::Foo) = g!(a, ROS(b))

julia> f!(foo, bar)
3

julia> g!(foo, bar)
ERROR: Cannot set property of ReadOnlyStruct
...

```

Someone could probably combine this into the `@immutable` macro.

An important concept here is that

- assigning to a property (`a_struct.property = value`) is just a call to `setproperty!(a_struct, :property, value)`
- assigning to an index (`array[idx] = value`) is just a call to `setindex!(array, idx, value)`

```julia
julia> @code_lowered f!(foo, bar|> ROS)
CodeInfo(
1 ─ Base.setproperty!(a, :x, 3)
└── return 3
)

julia> @code_lowered g!(foo, bar|> ROS)
CodeInfo(
1 ─ Base.setproperty!(b, :x, 3)
└── return 3
)

julia> h!(v) = v[1] = 5
h! (generic function with 1 method)

julia> @code_lowered h!(1:3)
CodeInfo(
1 ─ Base.setindex!(v, 5, 1)
└── return 5
)

```

Making the array or struct virtually “immutable” is thus just a matter of overriding the “set” methods for the wrapper type. Essentially what we are doing here is leveraging the power of multiple dispatch to implement a form of immutable arguments. This is wonderful since this avoids having to add additional keywords to Julia.

Earlier you suggested that the macro, `@immutable` should be part of `Base` Julia or the standard library. I disagree since this functionality can exist as an outside package. Julia has a minimalist design philosophy to its `Base` and standard libraries. If functionality can exist outside the standard libraries, then it should. A free standing package is much easier to iterate and evolve than if it were a standard library. There are many examples of packages that were once part of `Base` or a standard library which have since be spun out for this reason.

While more extensive language changes may not be possible now for Julia 1.x, it’s possible that they could be part of Julia 2.x or another major version iteration. Still the preference is to prototype new functionality outside in a package first to establish what needs to be done and how it may work.

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 3:00pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/67 "2022-08-22T15:00:55Z")

</div>

Wow tyvm for your time!

As was said before a couple of times:

Not the many ways of using a function is the problem, the lack of an enforced way of describing the side effects a function can have looking at its definition is.

---

<div class="post-metadata">

**Author:** ![mikmoore](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mikmoore/32/31109_2.png) [@mikmoore](https://discourse.julialang.org/u/mikmoore)\
**Post date:** [August 22, 2022, 3:12pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/68 "2022-08-22T15:12:53Z")

</div>

> [@mkitti](#):
>
> ```julia
> struct ReadOnlyStruct{T}
> parent::T
> end
> # and the following definitions...
> 
> ```

Nothing in Julia can stop a determined user from thwarting one’s attempts to simulate an object as immutable:

```julia
julia> instanceFoo = Foo(0)
Foo(0)

julia> immutableFoo = ReadOnlyStruct(instanceFoo)
ReadOnlyStruct{Foo}(Foo(0))

julia> getfield(immutableFoo,:parent).x = 1
1

julia> immutableFoo
ReadOnlyStruct{Foo}(Foo(1))

julia> instanceFoo
Foo(1)

```

It just isn’t supported by the language and its semantics. I have grossly violated the `ReadOnlyStruct`’s internals here, but the point stands. Personally, I consider the _ability_ to do this a feature, although one that needs to be exercised with extraordinary caution and only in very rare cases.

But it seems that the original poster’s needs and wants in this regard are not supported by Julia, nor will they be in the near or medium future, and they will perhaps be better-served by a different language.

---

<div class="post-metadata">

**Author:** ![stephancb](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stephancb/32/14243_2.png) [@stephancb](https://discourse.julialang.org/u/stephancb)\
**Post date:** [August 22, 2022, 3:13pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/69 "2022-08-22T15:13:34Z")

</div>

BTW, also in C++ the `const` does not guarantee that `r` will remain unchanged. Change

> [@Dan\_Micsa](#):
>
> `void f(const vector<double> &r) { r[0] = 2.0; }`

to

```julia
void f(const vector<double> &r) {
    const double *p = &r[0];
    const_cast<double*>(p)[0] = 2.0;
}

```

which will happily compile a function modifying the first element of `r`.

Generally `immutable`, i.e. impossible to change which is partially supported by Julia, but not for arrays, and `const` are different, as for example discussed [here](https://softwareengineering.stackexchange.com/questions/149555/difference-between-immutable-and-const)

---

<div class="post-metadata">

**Author:** ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)\
**Post date:** [August 22, 2022, 3:14pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/70 "2022-08-22T15:14:18Z")

</div>

I recommend taking a look at the effect analysis work that Jeff outlined in his State of Julia 2022 talk at the 10 minute mark. This is mostly being spearheaded by @aviatesk as far as I understand.

[![](https://global.discourse-cdn.com/julialang/original/3X/7/9/796a9a32b26a769ea50d0c51c3f247796a147a66.jpeg "The State of Julia (In 2022) with Jeff Bezanson | JuliaCon 2022") ](https://www.youtube.com/watch?v=N4h46_TCmGc&t=605s)

See [https://github.com/JuliaLang/julia/pull/46198](https://github.com/JuliaLang/julia/pull/46198) and related pull requests for more details. Besides the `Base.@assume_effects` macro there is also the `Base.@pure` macro that may be of interest.

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [August 22, 2022, 3:38pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/71 "2022-08-22T15:38:59Z")

</div>

> [@mkitti](#):
>
> Making the array or struct virtually “immutable” is thus just a matter of overriding the “set” methods for the wrapper type.

But there is no way to automatically delegate dispatch to the wrapped type, so `bar(::ROS{Foo})` won’t work, limiting the usefulness of this approach.

If we could automatically delegate all calls to the wrapped type, though…

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 3:42pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/72 "2022-08-22T15:42:26Z")

</div>

The designer of a library/function is not in charge to fool people but to help and inform.

This post is not about how we can hack in C++ is about how to inform about intended behaviour and side effects in a function declaration in Julia. That was the scope of the example.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 22, 2022, 4:00pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/73 "2022-08-22T16:00:42Z")

</div>

`ReadOnlyStruct` isn’t as substitutive as `ReadOnlyArray`, though. `ReadOnlyArray` is an `AbstractArray` that implements the entire `AbstractArray` interface minus the mutating `setindex!` by forwarding to the parent `AbstractArray`. Methods building on the `AbstractArray` interface that work on the parent will immediately work on the `ReadOnlyArray`. There isn’t any one interface for `mutable struct`s that `ReadOnlyStruct` can utilize like that e.g. you can’t immediately `getindex` a `ReadOnlyStruct{Dict}`. Besides, a immutable `struct` can be used to implement a mutable type that doesn’t reassign its fields e.g `Set`, `OffsetArray`.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 22, 2022, 4:57pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/74 "2022-08-22T16:57:21Z")

</div>

> [@Dan\_Micsa](#):
>
> The designer of a library/function is not in charge to fool people but to help and inform

I think you can say the same thing about Julia it just relies on documentation to tell the user of functions what the function does

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 5:02pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/75 "2022-08-22T17:02:40Z")

</div>

> [@dlakelan](#):
>
> I think you can say the same thing about Julia it just relies on documentation to tell the user of functions what the function does

Indeed, that’s the reason I started this thread, because the language doesn’t encourage/helps/forces this desired behaviour. This should not be coding guideliness / good practices should be forced and checked by the compiler.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 22, 2022, 5:23pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/76 "2022-08-22T17:23:04Z")

</div>

I think what we’ve established is that there are very few languages that actually offer any real hard guarantees about mutability (because most languages offer some “unsafe” way to cast things into other things etc) so in essence these const adornations and similar are largely documentary in nature with a little bit of additional help for the developer of the function to remind them when they’ve done something they shouldn’t have done such as assign to a variable relatively innocently just forgetting that they were not supposed to.

So the real question is what exactly do you want to get from Julia from these proposed ideas? You want it to throw errors that the developer of a function be reminded that they’ve done something wrong? If so we’ve got macros in this thread which helped with that.

If you want to somehow communicate to the user of the function Julia’s preferred method has been to use documentation strings. Those documentation strings are just something that languages like c++ simply don’t have because c++ has no interactive repl so there’s no clear way to query the “runtime” for what a function does. There are some IDE type aids but Julia has those as well.

In Julia if the function ends in exclamation point this is a big sign that something may be changed. To find out what you simply type `? functionname` and you get it’s documentation which should tell you what things can change and what things don’t so for the user I don’t see that we have any issue except that people could write bad documentation, but people could write bad documentation in any language, and people could fail to adorn consts and etc.

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 5:34pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/77 "2022-08-22T17:34:11Z")

</div>

Yes we had. I think realistically only Sing# a dialect of C# aspires to do this. But it doesn’t matter that we don’t have to defend that some malicious library implementer will cast something in implementation. We should care that expected behaviour is achieved. For example, in my case, I cast away constantness in some cached objects to load cached data from the disk. This doesn’t mean that I’m cheating casting but that I’m accelerating a calculation that was already done. that cast is done to set some flags in the wrapper about caching not the main expected behaviour. Are many examples why sometimes, is desired to cast away constatness that are not interested to discuss here because all this line of discussion about trickery, malicious behaviour, strength of languages are deeply out of my intended scope.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 22, 2022, 5:36pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/78 "2022-08-22T17:36:37Z")

</div>

Yes, but what **do** you want Julia to do? We have established that it’s possible to create code which aids the implementer in avoiding accidental mutation, and we have established that the normal method for communicating mutation behavior is documentation strings and a ! flag to let the user know there is expected mutation of some sort.

What else do you actually want Julia to do? I don’t really understand.

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 5:39pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/79 "2022-08-22T17:39:36Z")

</div>

That’s OK if you don’t understand. Read the initial post again.

---

<div class="post-metadata">

**Author:** ![dlakelan](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dlakelan/32/8491_2.png) [@dlakelan](https://discourse.julialang.org/u/dlakelan)\
**Post date:** [August 22, 2022, 5:45pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/80 "2022-08-22T17:45:37Z")

</div>

Fine, going back to the first post:

> [@Dan\_Micsa](#):
>
> I still don’t understand why parameters can be silently changed in function calls and why there is not a const or mutable like keyword to warn us if this is happening?

So we’ve established that there is a way to accomplish this… someone wrote a macro to do it elsewhere in this thread.

> [@Dan\_Micsa](#):
>
> I found that ‘!’ after the name of a mutable function useless for general usage with multiple parameters.

And we’ve established that the Julian way to do this is to provide a docstring that specifies the behavior of the function and what it mutates.

If you don’t like these things, can you say exactly what it is you’d like julia to do instead?

For example, I could imagine you wanting an error right after typing something like this:

```julia
function foo(a,b)
   a[1] = 1
   b[2] = 2
end

```

Because there’s no ! in the function name…

or right after something like this:

```julia
function foo!(a,const b)
   a[1] = 1
   b[2] = 2
end

```

because b was declared “const”

or something like that?

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [August 22, 2022, 5:59pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/81 "2022-08-22T17:59:19Z")

</div>

> [@Dan\_Micsa](#):
>
> the language doesn’t encourage/helps/forces this desired behaviour.

That’s certainly a valid opinion, one that is implemented in some languages. But I think people have laid out some big reasons why it’s not in Julia, which is your original question. Let me try to summarize the ones I’ve run across, I’ll rename your desired `const` as `Cpp_const` so nobody confuses it with Julia’s current `const`:

1. Like Python and very unlike C/C++, a Julia variable is not tied to an instance; an instance can be assigned to many variables, and a variable can change its instance (even the type) through reassignment. Is an instance allowed to be mutated if it assigned to a variable declared `Cpp_const` and another variable that isn’t? What if it is cyclically unassigned then reassigned to the `Cpp_const` variable, does it make sense for it to mutate then?

2. To enforce no attempts at mutation, one approach is to prove all used methods are non-mutating. However, Julia is not a statically typed, AOT compiled language. Arguments in methods often aren’t annotated with concrete types. So the compiler doesn’t have the necessary type information to even know what methods are used until a function is called at runtime with live input instances. This system gives us a lot of flexibility in composing code while only compiling what we need, but the method check happens way too late to smoothly enforce nonmutation.

3. Another approach is to somehow freeze the instance assigned to the `Cpp_const`ed variable. So what if it has a mutable type, just tell the compiler to not change any of its bits! That’s simple enough, right? Wrong, a Julia type often don’t “own” all of its data bits. An immutable struct with a mutable field doesn’t actually contain that mutable instance, just a pointer to it. Two different immutable struct instances can contain the same mutable instance by both having a field with the same pointer value. What happens when one instance is `Cpp_const`ed and the other is being mutated? Is that mutable field’s instance frozen for both? It’s not so different from the separation of pointers and their values in C++; [here’s](https://www.learncpp.com/cpp-tutorial/pointers-and-const/) a read about how their `const`-ness are separate.

4. Given how Julia treats its variables (see point 1) and how Julia doesn’t have pointers and references everywhere, Julia has a way to control mutability and immutability: as a property of a type. It’s usually dictated by the type definition `struct`/`primitive` vs `mutable struct`, but there were many exceptions pointed out. The only foolproof way is the documented description and methods of the type; for example, a `Set` is a `struct`, but it has a `push!` method that is unambiguous mutation. Some mutable types will have immutable counterparts e.g. `Dict` and `ImmutableDict`. It’s possible to make wrapper types to implement immutable counterparts in little code, but there’s limitations. The `ReadOnlyArray` is a pretty good way to wrap `AbstractArray`s into an immutable substitute, but it won’t work for everything e.g. methods specialized to other wrappers like `OffsetArray` won’t work on `ReadOnlyArray`.

---

<div class="post-metadata">

**Author:** ![Dan\_Micsa](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dan_micsa/32/30233_2.png) [@Dan\_Micsa](https://discourse.julialang.org/u/Dan_Micsa)\
**Post date:** [August 22, 2022, 6:04pm UTC](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091/82 "2022-08-22T18:04:21Z")

</div>

> [@dlakelan](#):
>
> So we’ve established that there is a way to accomplish this… someone wrote a macro to do it elsewhere in this thread.

There is not yet a way this is what we established. For neither problem.

What macro we have that works?  
What is mutable here: g!(a, b, c) ?

How this should be writen using that macro to assure a user that a and c are changed, for example, and how the compiler forces a implementer to do so? I still don’t understand how a mutable type (one that has mutable fields) will behave using that macro.

> > And we’ve established that the Julian way to do this is to provide a docstring that specifies the behavior of the function and what it mutates.

When the “Julian way” is not the strong way relying and not the language and compiler to do this but conventions and comments. I dont feel this is good enough solution by a large margin.

[Previous page](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091.md?page=3)

[Next page](https://discourse.julialang.org/t/why-i-cant-set-what-parameters-are-mutable-explicitly/86091.md?page=5)
