What's going on here? Appearently the last named function in the let
is treated as a toplevel function definition, but the second is not... on the other hand, the first assignment only points to the second method. What is the underlying logic of this?
EDIT: I got a method wrong in the example, see below for the corrected version.
What are you trying to achieve? fn2
declaraion is incorrect, since fn(x)
is not defined.
Ok, may be it's slightly different issue, but you can see similar error, even if you change named functions to anonymous
julia> (let fn = (i, x) -> x + 2, fn2 = x -> fn(x)
fn2
end)(1)
ERROR: MethodError: no method matching (::var"#7#9")(::Int64)
Closest candidates are:
(::var"#7#9")(::Any, ::Any) at REPL[4]:1
Nothing really to achieve concretely, I just was thinking about something like this during writing a macro. And I don't understand the behaviour.
The issue is not with the missing method of fn
(stupid me, I just forgot the first argument), but about why the named function creates a (globally visible) function at top level only with one method.
julia> f = let fn = function bar6(i, x) x + 2 end, fn2 = function bar6(x) fn(true, x) end
fn2
end
(::var"#bar6#34"{typeof(bar6)}) (generic function with 1 method)
julia> methods(bar6)
# 1 method for generic function "bar6":
[1] bar6(i, x) in Main at REPL[57]:1
julia> f(1)
3
julia> f = let fn = function bar7(i, x) x + 2 end, fn2 = function bar7(x) bar7(true, x) end
fn2
end
(::var"#bar7#35") (generic function with 1 method)
julia> f(1)
ERROR: MethodError: no method matching (::var"#bar7#35")(::Bool, ::Int64)
Closest candidates are:
(::var"#bar7#35")(::Any) at REPL[61]:1
Stacktrace:
[1] (::var"#bar7#35")(x::Int64)
@ Main ./REPL[61]:1
[2] top-level scope
@ REPL[62]:1
julia> methods(bar7)
# 1 method for generic function "bar7":
[1] bar7(i, x) in Main at REPL[61]:1
Why is bar7
treated as a closure within the second part of the let-block, whereas the first method is leaked outside?
This is on 1.7.0, BTW.
In non-global scope, named functions don't work at all:
julia> function outer()
f = let fun1 = function bar8(i, x) x + 2 end, fun2 = function bar8(x) fun1(true, x) end
fun2
end
end
outer (generic function with 1 method)
julia> outer()
ERROR: UndefVarError: fun1 not defined
Stacktrace:
[1] outer()
@ Main ./REPL[70]:2
[2] top-level scope
@ REPL[71]:1
julia> f = let fun1 = function bar8(i, x) x + 2 end, fun2 = function bar8(x) fun1(true, x) end
fun2
end
(::var"#bar8#40"{typeof(bar8)}) (generic function with 1 method)
julia> function outer()
f = let fun3 = ((i, x) -> x + 2), fun4 = ((x) -> fun3(true, x))
fun4
end
end
outer (generic function with 1 method)
julia> outer()
#42 (generic function with 1 method)
julia> outer()(1)
3
I always thought that a named function at non-global scope behaved just like a closure with a specifed name (which gets mangled into the generated symbol), but appearently it does make a difference.
Last updated: Dec 28 2024 at 04:38 UTC