Why is Julia messing up my variables?

Can one of you explain to me what is going on here and how to avoid it? Can you reproduce this behaviour?

When I define x as

x = zeros(10)
x .= .05
x 

I get

Vector{Float64} with 10 elements
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500

when I assign x to y:

y = x
x

I still get

Vector{Float64} with 10 elements
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500

but when I assign some values to some elements of y, my x values suddenly get messed up:

y[(1:10).<7] .= 1
x

gives

Vector{Float64} with 10 elements
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
0.0500
1.00
1.00
1.00

Can one of you explain me what I’m doing wrong here?

# Atom:
Version: 1.41.0
Dev Mode: false
Official Release: true
{
  "http_parser": "2.8.0",
  "node": "10.11.0",
  "v8": "6.9.427.31-electron.0",
  "uv": "1.23.0",
  "zlib": "1.2.11",
  "ares": "1.14.0",
  "modules": "69",
  "nghttp2": "1.33.0",
  "napi": "3",
  "openssl": "1.1.0",
  "electron": "4.2.7",
  "chrome": "69.0.3497.128",
  "icu": "62.2",
  "unicode": "11.0",
  "cldr": "33.1",
  "tz": "2019a"
}
# julia-client:
Version: 0.11.3
Config:
{
  "firstBoot": false,
  "uiOptions": {
    "enableMenu": true,
    "enableToolBar": true
  }
}


# ink:
Version: 0.11.7
Config:
undefined


# uber-juno:
Version: 0.3.0
Config:
{
  "disable": true
}


# language-julia:
Version: 0.19.2
Config:
undefined


# language-weave:not installed


# indent-detective:
Version: 0.4.0
Config:
undefined


# latex-completions:
Version: 0.3.6
Config:
undefined


# versioninfo():
Julia Version 1.3.0
Commit 46ce4d7933 (2019-11-26 06:09 UTC)
Platform Info:
  OS: Linux (x86_64-pc-linux-gnu)
  CPU: Intel(R) Core(TM) i5-8250U CPU @ 1.60GHz
  WORD_SIZE: 64
  LIBM: libopenlibm
  LLVM: libLLVM-6.0.1 (ORCJIT, skylake)
Environment:
  JULIA_NUM_THREADS = 4

    Status `/home/local/kohlluka/.julia/environments/v1.3/Project.toml`
  [c52e3926] Atom v0.11.3
  [e5e0dc1b] Juno v0.7.2

Julia like most other high level languages (oppose C) think of variables as pointers to data. Thus y=x doesn’t mean “make y hold a copy of x”, but instead means “make y a synonym for x”. Thus changing y, naturally, changes x. If you want a copy, you should instead write y=copy(x).

10 Likes

thanks for your help!

In addition, you may also find the behavior shown below helpful to keep in mind as a reference. Array slicing (things like a[:] where a is an array) also copies the underlying vector.

########################
       Example 1
########################

julia> a = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

#creates a copy of a so changing b won't change a
julia> b = a[:]
3-element Array{Int64,1}:
 1
 2
 3

julia> b[1]
1

julia> b[1] = 4
4

julia> b
3-element Array{Int64,1}:
 4
 2
 3

julia> a
3-element Array{Int64,1}:
 1
 2
 3

########################
      Example 2 
########################

julia> a = [1, 2, 3]
3-element Array{Int64,1}:
 1
 2
 3

#b is synonymous with a so changing b will change a
julia> b = a
3-element Array{Int64,1}:
 1
 2
 3

julia> b[1]
1

julia> b[1] = 4
4

julia> b
3-element Array{Int64,1}:
 4
 2
 3

julia> a
3-element Array{Int64,1}:
 4
 2
 3

For more information, I would encourage reading “Gotcha #5: Views, Copy and Deepcopy” in

1 Like

What is the advantage of using pointers to same data when we write b = a? When we create a new variable with the value of old, it is usually to modify the data in the new one. Even though I have seen this behavior in other languages also, I’m yet to understand why such a “confusing” behavior is so widespread in many languages?

The behavior is useful because copying data can be expensive. Saying b = a avoids a copy. Moreover, it’s sometimes useful to keep the same array in different forms without copying the underlying data. Again, the behavior of b = a let’s you achieve that.

See the following quote from https://www.stochasticlifestyle.com/7-julia-gotchas-handle/

"(Such behavior) is very useful because it also allows you to keep the same array in many different forms. For example, we can have both a matrix and the vector form of the matrix using:

a = rand(2,2) # Makes a random 2x2 matrix
b = vec(a) # Makes a view to the 2x2 matrix which is a 1-dimensional array

Now “b” is a vector, but changing “b” still changes “a”, where “b” is indexed by reading down the columns. Notice that this whole time, no arrays have been copied, and therefore these operations have been excessively cheap (meaning, there’s no reason to avoid them in performance sensitive code)."

1 Like

@bashonubuntu Thanks a lot for the explanation. The example you provided makes the reason more clear. :slight_smile:

1 Like

Glad to hear!

But then why would you need to make b = a and not just keep using a?

b = a is quite rare to write but consider

b = [[1,2,3], [4,5,6]]
a = b[1]

or passing a variable into a function.

3 Likes