I don't understand why or how y(:,i) = x creates a function

I’m very new to Julia, but not to coding, having spent the last decade or so mostly in Matlab (and a variety of other languages stretching back to the mists of time…). So I’ve been toying around with some simple projects in Julia, and I’ve run into something I don’t understand. Here’s a stripped version of the code:

function testret(n)
    y = zeros(Float64, n, n)
    for i=1:n
        x = ones(Float64,n) .* i
        y(:,i) = x
    end
    return y
end

In my Matlabese I wanted to assign to a slice of the y array. It took me some time to figure out that I need to use square brackets for this, but eventually I got there… however, I still don’t understand why the version above works, or what it really does.

julia> f  = testret(10)
(::var"#y#104"{Array{Float64,1}}) (generic function with 1 method)

So it looks the y(:,i) = x assignment creates a function of some kind (?). Values of f always return an array of 10s, so it’s only the last assignment that matters.

To make things even more confusing for me, if I replace y(:,i) = x with y(:,i) = ones(Float64,n) .* i the behavior subtly changes. First, original case (repeat output values omitted):

julia> f
(::var"#y#120"{Array{Float64,1}}) (generic function with 1 method)

julia> f(1,1)
10-element Array{Float64,1}:
 10.0

julia> f(100,1)
10-element Array{Float64,1}:
 10.0

julia> f(1,5)
10-element Array{Float64,1}:
 10.0

and the second case:

julia> f
(::var"#y#116"{Int64}) (generic function with 1 method)

julia> f(1,1)
10-element Array{Float64,1}:
1.0

julia> f(100,1)
10-element Array{Float64,1}:
1.0 

julia> f(1,5)
10-element Array{Float64,1}:
 5.0 

I obviously don’t understand something fundamental about Julia’s syntax here, so any pointers as to where I should look would be welcome!

You want y[:,i] = x. Square brackets are used for indexing.

1 Like

f(:,i) = x makes a function f, which takes two arguments, and returns x. It doesn’t actually use either of the arguments, and it doesn’t matter that the function argument name : has special meaning in indexing (but is also the range operator) or that the other argument name i is the same as that of a local variable in the enclosing function. That’s all irrelevant.

1 Like

f(:,i) = x makes a function f , which takes two arguments, and returns x . It doesn’t actually use either of the arguments, and it doesn’t matter that the function argument name : has special meaning in indexing (but is also the range operator) or that the other argument name i is the same as that of a local variable in the enclosing function. That’s all irrelevant.

Thank you, that does clarify it considerably for me!

You want y[:,i] = x . Square brackets are used for indexing.

Indeed I do! I was able to figure that out (eventually), but what really mystified me was why the syntax with regular parentheses compiled and ran.

If you want to create a vector of a single value, this isn’t really the recommended way, BTW, since it creates a temporary array, then does a bunch of multiplications to create the second, final, array. Instead, you can use the fill function:

x = fill(float(i), n)  # float turns i into a float value

(Of course, you could just do y[:, i] .= i directly, with zero instead of two intermediate arrays, in Julia and, y(:, i) = i in Matlab.)

2 Likes

I would like to think I would have written it that way in both languages, had it not been for the demands of the MWE here… thank you for pointing it out though! The explicit requirement to specify broadcasting in Julia takes some getting used to, as Matlab will often implicitly broadcast across functions and assignments.