# Error missing about side-effect on immutable type

**URL:** <https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588>\
**Category:** General Usage\
**Created:** [January 20, 2020, 2:47pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588 "2020-01-20T14:47:44Z")\
**Posts on this page:** 12\
**Page:** 1

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [January 20, 2020, 2:47pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/1 "2020-01-20T14:47:44Z")

</div>

[docs](https://docs.julialang.org/en/v1.3/manual/functions/#Argument-Passing-Behavior-1) mentioned that:

> Julia function arguments follow a convention sometimes called “pass-by-sharing”… Modifications to mutable values (such as `Array` s) made within a function will be visible to the caller.

I think it causes a bit of confusion, especially if we’re defining “wrong” side-effect functions on immutables, e.g.

```julia
julia> x = 1
1

julia> f!(a) = a+=2
f! (generic function with 1 method)

julia> f!(x)
3

julia> x
1

julia> isimmutable(x)
true

```

here we call `f()` with the immutable `x` does **not** throw any error.

moreover, sometimes `isimmutable()` is **not** a reliable check:

```julia
julia> y = [11, 12, 13];

julia> vy = @view y[1:3];

julia> isimmutable(y)
false

julia> isimmutable(vy)
true

julia> f2!(b) = b .+= 3
f2! (generic function with 1 method)

julia> f2!(y)
3-element Array{Int64,1}:
 14
 15
 16

julia> f2!(vy)
3-element view(::Array{Int64,1}, 1:3) with eltype Int64:
 17
 18
 19

```

noted that a `view` is **im** mutable! (according to `isimmutable()`), yet apparently it’s often been used in `!` functions.

another example:

```julia
julia> t = (1, 2)
(1, 2)

julia> g!(a) = a[1]+=2
g! (generic function with 1 method)

julia> g!(t)
ERROR: MethodError: no method matching setindex!(::Tuple{Int64,Int64}, ::Int64, ::Int64)

```

now an `MethodError` is thrown, but it’s not about side-effect on immutables.  
so, if I’m crazy enough to do:

```julia
julia> Base.setindex!(tup::Tuple{Int, Int}, v::Int, i::Int) = setfield!(tup, 1, v)

julia> g!(t)
ERROR: setfield! immutable struct of type Tuple cannot be changed

```

finally a relevant error is thrown, yet it is of the generic type `ErrorException`.

should we define an error type of it? and throw the error as long as it happens?  
thanks.

---

<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 20, 2020, 2:57pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/2 "2020-01-20T14:57:54Z")

</div>

> [@tomtom](#):
>
> especially if we’re defining “wrong” side-effect functions on immutables […]
> 
> ```julia
> f!(a) = a+=2
> 
> ```

That code doesn’t mutate the _contents_ `a` at all. You would need `.+=` or similar (if it was an array).

> [@tomtom](#):
>
> now an `MethodError` is thrown, but it’s not about side-effect on immutables.

I am not sure what kind of error you were expecting, and why.

In general, it is not the job of the compiler to figure out the _intent_ of your code. You can also write things like

```julia
g!(a) = a

```

which, again, does not mutate anything at all.

Or one can design an API that may or may not mutate (depending on the actual type), and asks you do use the returned value in all cases (eg this is common for dealing with potentially immutable `<:AbstractArray`s).

> [@tomtom](#):
>
> finally a relevant error is thrown, yet it is of the generic type `ErrorException` .

All errors you get above are relevant. And this one has a perfectly fine error message. Why do you want a narrower error type — do you need to dispatch on this?

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [January 20, 2020, 3:09pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/3 "2020-01-20T15:09:12Z")

</div>

> [@Tamas\_Papp](#):
>
> That code doesn’t mutate the _contents_ `a` at all.

yes I know. But the **confusion** I mean is the sentence [Julia function arguments follow a convention sometimes called “pass-by- **sharing**"].  
In Julia, `f(x)` is actually passing by **value** (not sharing) if `x` is atomic, but the same syntax `f(x)` is passing by reference if `x` is a `Vector`. So, the above sentence in docs is not entirely correct I think.

by the way, what is `f(x)` passing if `x` is a `struct`? the copied structure or the reference? thanks.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [January 20, 2020, 3:20pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/4 "2020-01-20T15:20:41Z")

</div>

> [@tomtom](#):
>
> In Julia, `f(x)` is actually passing by **value** (not sharing) if `x` is atomic, but the same syntax `f(x)` is passing by reference if `x` is a `Vector` .

No this is totally wrong. If you do `f!(x) = (a = a .+ 2)` and do `x = 1; f!(x)` or `x = [1]; f!(x)`, `x` will not be mutated in either case.

There’s basically nothing to error in this case since the only mistake you make as far as the compiler could possibly tell is that you are doing an assignment that is not used again. Such thing should be at most a warning and really belongs to a linter instead of a compiler.

The error about `setindex!` on tuples could be better. It would not change the error thrown but would be a logic in printing `MethodError` on `setindex!` with immutable object as first argument. We have a lot of special case to print user friendly error messages like this already so that’s a pretty reasonable thing to do.

> [@tomtom](#):
>
> by the way, what is `f(x)` passing if `x` is a `struct` ? the copied structure or the reference? thanks.

As I said, it’s always by reference semantically.

---

<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 20, 2020, 3:28pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/5 "2020-01-20T15:28:31Z")

</div>

Everything is passed “by value”. That value can be a container, potentially with mutable contents. But it is still a value.

The whole “by value” / “by reference” distinction, as understood in languages like C/C++, is not really useful for programming Julia.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [January 20, 2020, 3:43pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/6 "2020-01-20T15:43:41Z")

</div>

> [@yuyichao](#):
>
> As I said, it’s always by reference semantically.

> [@Tamas\_Papp](#):
>
> Everything is passed “by value”.

sorry … I’m still confused…  
by **experience** , yes, I know the correct use cases for various kinds of variables. Yet **conceptually** I’m confused. (and sorry for not able to explain well…)

as far as I understand, please correct me for any wrong concept:

1. `x = 1` binds the name `x` to the value `1` (which is stored somewhere).
2. a later expression `x = 2` would (re)bind the name `x` to **another** value (which is stored **else** where)

but… why is the following?

```julia
julia> x
1

julia> Ref(x)[] = 2
2

julia> x
1

```

(again, as far as I understand) this should set the value where `x` has bound to (i.e. **overwrite** the value `1` by `2`) ? but why not happening??? also, no error is thrown but the assignment has no effect…

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [January 20, 2020, 4:05pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/7 "2020-01-20T16:05:47Z")

</div>

> [@tomtom](#):
>
> `julia> Ref(x)[] = 2`

1. Forget about the name `Ref`. It does not create a mutable reference to the object that is passed in. It does create a **reference** to the object passed in, but it does not mean you can **mutate** that object. If you expect such a semantics from other language then no this is not a reference in that sense. If you aren’t expecting that from the name then never mind about this point…

2. `Ref(x)[] = 2` is equivalent to (bearing additional variable conflicts…) `y = Ref(x); y[] = 2`. Similar to what you said. `Ref(x)` creates a reference that’s bound to `1`. This object is then assigned to `y`. `y[] = 2` then store a different object into `y`. Since `y` isn’t `x` (only the reference of the object was passed in, not the reference to the variable) the second assignment has absolutly no effect on `x`. (In fact, nothing can, except assignment to `x` directly).

I’m not sure what you are confused about but a few other things to emphasis again:

1. There is no referene to **variable**. All reference are reference to **objects** (values)

2. `Ref(x)` indeed creates an object that refer to the same object as `x`. However, this does not mean that the reference cannot be rebound. In fact, that’s exactly what `y[] = 2` does. Given the previous emphasis point, this is the only reasonable behavior.

* * *

> [@tomtom](#):
>
> (which is stored somewhere).

> [@tomtom](#):
>
> (which is stored **else** where)

I know these expressions can sometimes be useful but no they are not stored anywhere. (i.e. don’t take these expression literally and don’t use these as argument for anything…).

Storage location doesn’t exist as a concept when you talk about high level semantics (an object (value) is an object (value), it’s abstract and isn’t bind to any memory). At low level this is also not the case. `1` may or may not be anywhere. `2` may or may not be stored at the same location as the `1` or it may or may not be stored anywhere.

There really isn’t a level where you can talk about 1 and 2 stored at different locations. You can talk about a equivalent unoptimized implementation using other languages (like C++) where these could be the case if that helps your understanding. Just be careful what you are talking about is a property of the language and what is the property of your implementation.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [January 20, 2020, 4:13pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/8 "2020-01-20T16:13:11Z")

</div>

> [@Tamas\_Papp](#):
>
> Everything is passed “by value”. That value can be a container, potentially with mutable contents. But it is still a value.

There may not be multiple kind of passing semantics but saying everything is passed “by value” would be very misleading. The different names (by value, by reference, by sharing) is indeed a bit ambiguous but I believe by value usually does not mean what we have. I usually use by reference since it seems to be understood by most people but I’m also fine with by sharing.

AFAICT, “by value” usually imply copying, and mutating the passed object will have no effect on the original one. Such semantics doesn’t exist in julia but that doesn’t mean this is a correct or good way to describe the argument passing semanatics. Copying (and aliasing) is definately an object that exist in julia and calling this by value is only going to cause unnecessary confusion.

---

<div class="post-metadata">

**Author:** ![tomtom](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tomtom/32/5106_2.png) [@tomtom](https://discourse.julialang.org/u/tomtom)\
**Post date:** [January 20, 2020, 4:21pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/9 "2020-01-20T16:21:07Z")

</div>

> [@yuyichao](#):
>
> Forget about the name `Ref`

> [@yuyichao](#):
>
> this does not mean that the reference cannot be rebound

I mean, the following example really confuses me:

```julia
julia> x = 1;

julia> y = Ref(x);

julia> y == Ref(x)
false

julia> Ref(x) == Ref(x)
false

```

by any sense, a `Ref` is “not a reference” is … just confusing. I think we need another term to clarify the situation…

---

<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 20, 2020, 4:25pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/10 "2020-01-20T16:25:06Z")

</div>

> [@yuyichao](#):
>
> Such semantics doesn’t exist in julia but that doesn’t mean this is a correct or good way to describe the argument passing semanatics.

Certainly — hence the quotation marks. As I said above, this kind of terminology is not a useful one for Julia. It is unfortunate that it is so widespread.

> [@tomtom](#):
>
> but… why is the following?

Think of `Ref` as a container for a single value. It has nothing to do with the `&` operator in C.

---

<div class="post-metadata">

**Author:** ![Sukera](https://avatars.discourse-cdn.com/v4/letter/s/ce7236/32.png) [@Sukera](https://discourse.julialang.org/u/Sukera)\
**Post date:** [January 20, 2020, 4:45pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/11 "2020-01-20T16:45:47Z")

</div>

> [@tomtom](#):
>
> ```julia
> julia> Ref(x) == Ref(x)
> false
> 
> ```

Maybe this will help: `Ref(x)` creates a new object referring to `x`. `Ref(x) == Ref(x)` creates _two distinct_ objects referring to `x`. The equality check returns `false` because there is no specialised method for `==(::Ref, ::Ref)`, and thus the generic fallback to identity/`===` happens.

```julia
julia> x = 1
1

julia> @which Ref(x) == Ref(x)
==(x, y) in Base at operators.jl:83

# @edit Ref(x) == Ref(x) shows us this:
# ==(x, y) = x === y

```

Now, as for this:

> [@tomtom](#):
>
> ```julia
> julia> f!(a) = a+=2
> f! (generic function with 1 method)
> 
> julia> f!(x)
> 3
> 
> ```

Your function is equivalent to the following definition:

```julia
function f!(a)
   a = a+2
   return a
end

```

The variable `a` in the body of the function is reassigned a new value and that new value is returned, because in julia the value of the last executed statement is also returned from the function. The variable outside of `f!` is still referring to the old value, because it is in a different scope and nothing inside of the function is modifying what’s inside of that value.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [January 20, 2020, 4:46pm UTC](https://discourse.julialang.org/t/error-missing-about-side-effect-on-immutable-type/33588/12 "2020-01-20T16:46:48Z")

</div>

> [@tomtom](#):
>
> by any sense, a `Ref` is “not a reference” is … just confusing

Well it’s not a C++ reference, which is by no mean the only meaning of it. It is refering to a single object.

> [@tomtom](#):
>
> ```julia
> julia> x = 1;
> 
> julia> y = Ref(x);
> 
> julia> y == Ref(x)
> false
> 
> julia> Ref(x) == Ref(x)
> false
> 
> ```

Well, try this in C. `int x = 0, y = 0; return &x == &y;`.
