Function definitions are possible in for-loop header #53738
Open
Description
Yesterday I found out that in a loop header values can be assigned to array elements:
julia> a = [77];
julia> for a[1] = 1:5
println(a)
end
[1]
[2]
[3]
[4]
[5]
which seems a bit niche but ok.
Naturally, I tried other uses of =
in the loop header: setting mutable struct fields works and function definition as well. But the latter produces strange results:
julia> function for_loop_fn()
function f end
for f(i) = 1:2
println(f(1))
end
return f
end;
julia> fn = for_loop_fn()
1
2
(::var"#f#4"{Int64}) (generic function with 1 method)
julia> fn(77)
2
Also actually using i
in the "function body" does not work (and probably can't):
julia> for f(i) = 1:2+i
println(f(1))
end
ERROR: UndefVarError: `i` not defined
Stacktrace:
[1] top-level scope
@ REPL[14]:1
Should the function definition just error? Or is there a purpose to this?
For reference, the lowered code:
julia> @code_lowered for_loop_fn()
CodeInfo(
1 ─ Core.NewvarNode(:(f))
│ %2 = 1:2
│ @_2 = Base.iterate(%2)
│ %4 = @_2 === nothing
│ %5 = Base.not_int(%4)
└── goto #4 if not %5
2 ┄ %7 = @_2
│ @_4 = Core.getfield(%7, 1)
│ %9 = Main.:(var"#f#4")
│ %10 = Core.typeof(@_4)
│ %11 = Core.apply_type(%9, %10)
│ f = %new(%11, @_4)
│ %13 = Core.getfield(%7, 2)
│ %14 = (f)(1)
│ Main.println(%14)
│ @_2 = Base.iterate(%2, %13)
│ %17 = @_2 === nothing
│ %18 = Base.not_int(%17)
└── goto #4 if not %18
3 ─ goto #2
4 ┄ return f
)
This is in Julia 1.10.2. However, a quick check suggests it's identical down to 1.2. In 1.1 there is slightly different but still wrong behavior (but array element updating also works).