How to get anonymous function from its type?

f = x -> x + 1
T = typeof(f)
# ==> var"#2#4"

Given a type T of an anonymous function, can I get that function? I.e. given var#"2#4" get object f?

I get the type T from the lowered representation of code (actually, from IRTools, but it’s nearly the same in this context). E.g.:

@code_lowered (xs -> [x + 1 for x in xs])(rand(5))
# ==> CodeInfo(
# ==> 1 ─      #2 = %new(Main.:(var"#2#4"))
# ==> │   %2 = #2
# ==> │   %3 = Base.Generator(%2, xs)
# ==> │   %4 = Base.collect(%3)
# ==> └──      return %4
)

In IR, we have a special instruction %new which constructs the function, but I can’t find a language or compiler feature to do it from my code.

For singleton types (such as anonymous functions which aren’t closures), you can access the instance from the instance field:

julia> f = x -> x + 1
#1 (generic function with 1 method)

julia> T = typeof(f)
var"#1#2"

julia> T.instance
#1 (generic function with 1 method)
6 Likes

Because of context switch I didn’t realize this approach doesn’t work for UnionAll types like in the example with the generator:

@code_lowered (xs -> [x + 1 for x in xs])(rand(5))
# ==> CodeInfo(
# ==> 1 ─      #130 = %new(Main.:(var"#130#132"))
# ==> │   %2 = #130
# ==> │   %3 = Base.Generator(%2, xs)
# ==> │   %4 = Base.collect(%3)
# ==> └──      return %4
# ==> )
T = var"#130#132"
T.instance
# ==> ERROR: type UnionAll has no field instance
T.body.instance
# ==> ERROR: UndefRefError: access to undefined reference
T{:x}.instance
# ==> ERROR: UndefRefError: access to undefined reference

Any directions on how to refer to the underlying function (essentially, x + 1) in this example?

After many experiments I came up with the following utility function which can instantiate any objects including anonymous functions:

@generated function __new__(T, args...)
    return Expr(:splatnew, :T, :args)
end

Example:

julia> @code_lowered (xs -> [x + 1 for x in xs])(rand(5))
CodeInfo(
1 ─      #58 = %new(Main.:(var"#58#60"))
│   %2 = #58
│   %3 = Base.Generator(%2, xs)
│   %4 = Base.collect(%3)
└──      return %4
)

julia> T = var"#58#60"
var"#58#60"

julia> f = __new__(T)
#58 (generic function with 1 method)

julia> f(1)
2
1 Like