Evaluating the "for" condition

Hello everyone. The following simple example is just to ask the question: will Julia evaluate the length function 5 times? Thank you.

function test()
	v = [1,2,3,4,5]
	for i = 1:length(v)
		println(v[i])
	end
end

No

1 Like

A quick and no-brainer way to check if performance is affected (while not answering your question exactly):

using BenchmarkTools

v = [1:10_000]

function test1(v)
	for i = 1:length(v)
		println(v[i])
	end
end

@btime test1(v)
120.894 ΞΌs (22 allocations: 800 bytes)

function test2(v)
    n = length(v)
	for i = 1:n
		println(v[i])
	end
end

@btime test2(v)
121.065 ΞΌs (22 allocations: 800 bytes)

1 Like

The key thing to understand here is that 1:length(v) is just an ordinary Julia expression that creates a β€œrange” object storing the endpoints. This object gets evaluated once, before the for loop starts, and gets re-used on every iteration as needed.

More generally, whenever you do for x = X or (equivalently) for x in X, for any expression X, the expression X is evaluated once and then the resulting iterable object is re-used during the loop.

4 Likes

I only knew @time, I liked @btime, very good!

Thank @lmiq, @ptoche and @stevengj.

2 Likes

I tend to avoid the combination of @btime and println. How far do you have to scroll back up to compare the results?

In the OP’s code, it’s just something to do inside the loop.

julia> length(v)
1

Though your example is still valid perhaps you meant v=[i for i in 1:10_000]?

perhaps you meant v=[i for i in 1:10_000] ?

I meant something big that’s all.

You can see it explicitely with:

julia> function test()
           v = [1,2,3,4,5]
           for i = 1:length(v)
               println(v[i])
           end
       end
test (generic function with 1 method)

julia> @code_lowered test()
CodeInfo(
1 ─       v = Base.vect(1, 2, 3, 4, 5)
β”‚   %2  = Main.length(v)
β”‚   %3  = 1:%2
β”‚         @_2 = Base.iterate(%3)
β”‚   %5  = @_2 === nothing
β”‚   %6  = Base.not_int(%5)
└──       goto #4 if not %6
2 β”„ %8  = @_2
β”‚         i = Core.getfield(%8, 1)
β”‚   %10 = Core.getfield(%8, 2)
β”‚   %11 = Base.getindex(v, i)
β”‚         Main.println(%11)
β”‚         @_2 = Base.iterate(%3, %10)
β”‚   %14 = @_2 === nothing
β”‚   %15 = Base.not_int(%14)
└──       goto #4 if not %15
3 ─       goto #2
4 β”„       return nothing
)