# Extract function from function type

**URL:** <https://discourse.julialang.org/t/extract-function-from-function-type/90651>\
**Category:** General Usage\
**Tags:** type, functions\
**Created:** [November 22, 2022, 4:06pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651 "2022-11-22T16:06:07Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 4:06pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/1 "2022-11-22T16:06:07Z")

</div>

Consider the following:

```julia
foo(x) = x
foo_type = foo |> typeof

# Don't know how to implement but I know what I want it to do
# Example: default(foo_type) -> foo
default(::Type{T}) where T <: Function = ???

# The following code works but is not generic
default(::Type{foo_type}) = foo

```

How can I implement the first version of default that is generic?

Basically my function `default` takes a type and returns a default value of said type which I use in combination with a Bool to mimic uninitialized values. I want to be able to do the same with functions.

I am aware of `missing` and `nothing`. And I am also aware that union splitting removes the performance impact from the type instability they cause. However, in my specific use case I am not interested in that as a solution.

I am also aware that I could use a macro to add the hard coded version of the function automatically. But I use macros only as a last resort.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 4:31pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/2 "2022-11-22T16:31:04Z")

</div>

Here you go:

> [@How to get a function instance from a function type?](https://discourse.julialang.org/t/how-to-get-a-function-instance-from-a-function-type/79585/2):
>
> No, because not all functions have a one-to-one relationship with their types. For instance, f = let x = 1 y -\> x + y end captures runtime data and cannot be reconstructed from it’s type alone. That said, in the case of functions which are singleton instances, you could do if isdefined(tf, :instance) ft.instance else error("This type does not have a single instance") end

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 4:44pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/3 "2022-11-22T16:44:37Z")

</div>

The second hardcoded version works even if there are multiple instances of the function.

Namely I am not looking to get back a specific method of the function but rather the function itself which does have a 1 to 1 relationship with the type

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 5:01pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/4 "2022-11-22T17:01:04Z")

</div>

> [@HashBrown](#):
>
> Namely I am not looking to get back a specific method of the function but rather the function itself which does have a 1 to 1 relationship with the type

I wasn’t talking about methods, I was talking about functions themselves. One function type can have multiple instances in the case of things like closures.

```julia
julia> f = let x = 1
           y -> x + y
       end
#5 (generic function with 1 method)

julia> dump(f)
#5 (function of type var"#5#6"{Int64})
  x: Int64 1

julia> f2 = eval(Expr(:new, typeof(f), 2))
#5 (generic function with 1 method)

julia> dump(f2)
#5 (function of type var"#5#6"{Int64})
  x: Int64 2

```

```julia
julia> f2(1)
3

julia> f(1)
2

```

Most importantly here,

```julia
julia> typeof(f2) == typeof(f)
true

julia> f2 == f
false

```

This is because the way we implement closures is that they’re really `struct`s carrying data representing the closed over variables, so they’re not uniquely defined by their type alone.

Notice here that both `f` and `f2` have only one method in my example, so this is completely orthogonal to the question of how many methods a function has.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 5:07pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/5 "2022-11-22T17:07:55Z")

</div>

As I said in the linked discussion though, if you want to ignore those corner cases, you can write something like

```julia
function default(::Type{ft}) where {ft <: Function}
    if isdefined(ft, :instance)
        ft.instance
    else 
        error("This type does not have a single instance")
    end
end

```

which will work for most functions, but can definitely fail for the reasons I’ve described.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 5:10pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/6 "2022-11-22T17:10:39Z")

</div>

Ah I see. Sorry I thought methods and instances were the same, but thank you for correcting me on that.

I think I should be fine not being able to handle that corner case. Thanks

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 5:21pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/7 "2022-11-22T17:21:58Z")

</div>

Actually a follow up. In my case I just need a value of the type. In other words it does not have to be any particular instance, just an instance.

So even if there is not a 1-1 matching that would be fine for me. Is there a way to get an instance regardless of whether it is a single instance or not?

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 8:47pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/8 "2022-11-22T20:47:10Z")

</div>

@HashBrown Do you mind if I ask what are you actually trying to do here? It may be that there’s a smarter way to get what you want here…

Regardless though, yes, it is in fact possible for you to get _a_ instance of any type (including functions) which uninitialized values in any slots. Doing this requires mucking around with some internals, and this can get dangerous. Here’s how I’d do it:

```julia
@generated function new(::Type{T}, args...) where {T}
    Expr(:new, T, (:(args[$i]) for i ∈ 1:length(args))...)
end;

any_instance(::Type{T}) where {T} = new(T);

```

For single instance types, this just gives you the type:

```julia
julia> any_instance(Missing)
missing

julia> any_instance(typeof(sin))
sin (generic function with 14 methods)

```

For structs and whatever that only store inline bits, it’ll give you garbled random bits:

```julia
julia> any_instance(Int)
139702373082064

julia> f = let x = 1
           y -> x + y
       end
#8 (generic function with 1 method)

julia> any_instance(typeof(f)) |> dump
#8 (function of type var"#8#9"{Int64})
  x: Int64 139734222465888

julia> any_instance(typeof(f))(1)
139734222465889

```

And for structs which are storing pointer-backed types, this gives undefined references (which at least are slightly safer than null pointers)

```julia
julia> struct Foo
           x::Any
       end

julia> let foo = any_instance(Foo)
           dump(foo)
       end
Foo
  x: #undef

julia> let foo = any_instance(Foo)
           foo.x
       end
ERROR: UndefRefError: access to undefined reference
Stacktrace:
 [1] getproperty(x::Foo, f::Symbol)
   @ Base ./Base.jl:38
 [2] top-level scope
   @ REPL[5]:2

```

* * *

Again though, I want to reiterate that I suspect that this isn’t actually the right path, and if you tell us what you’re actually trying to achieve we can probably give a better suggestion.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 10:30pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/9 "2022-11-22T22:30:52Z")

</div>

I noticed that `any_instance(Tuple{Int64, String})` is crashing Julia. Is that expected?

As for what I am working on, it is rather hard to explain. But basically I am creating a bunch of `const Ref` types in global scope and functions that control access to them through metaprogramming (another thing I am sure you will advise me against 😉). I need to initialize them with something and for the sake of type stability and ease in other ways I don’t want to use `missing`.

Also on the implementation of `new` I am not really following what `args...` is doing.

When I write:

```julia
struct Foo
    a::Int64
end

Expr(:new, Foo) |> eval # ERROR: invalid struct allocation

```

Which to me seems like it should work based on your function definitions.

Obviously the following works:

```julia
Expr(:new, Foo, Expr(:new, Int64)) |> eval

```

but I don’t see how that is analogous to the code you posted.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 10:38pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/10 "2022-11-22T22:38:09Z")

</div>

> [@HashBrown](#):
>
> I noticed that `any_instance(Tuple{Int64, String})` is crashing Julia. Is that expected?

It’s not crashing julia. Trying to diplay it in the REPL is crashing julia.

```julia
julia> let x = any_instance(Tuple{Int, String})
           dump(x)
       end
Tuple{Int64, String}
  1: Int64 0
  2: #undef

```

That’s expected yes, because as I explained above, this will end up with an undefined reference, and accessing undefined references isn’t allowed.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 10:44pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/11 "2022-11-22T22:44:07Z")

</div>

I edited the above to include a follow up question. Sorry, I should have posted it as a reply, but I think I edited it while you were responding.

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 10:56pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/12 "2022-11-22T22:56:19Z")

</div>

> [@HashBrown](#):
>
> Also on the implementation of `new` I am not really following what `args...` is doing.
> 
> When I write:
> 
> ```julia
> struct Foo
> a::Int64
> end
> 
> Expr(:new, Foo) |> eval # ERROR: invalid struct allocation
> 
> ```
> 
> Which to me seems like it should work based on your function definitions.
> 
> Obviously the following works:
> 
> ```julia
> Expr(:new, Foo, Expr(:new, Int64)) |> eval
> 
> ```
> 
> but I don’t see how that is analogous to the code you posted.

Yeah, for some reason `Expr(:new)` works differently in a generated function than in macros or `eval`. I believe this is because the lowering process adds a hook to try and protect users from making an instance of a struct with undefined fields, and maybe there’s a missing branch in the generated function lowering that lets us evade this restriction. Not sure.

But either way, compare:

```julia
julia> @generated foo() = Expr(:new, Foo);

julia> foo()
Foo(140229810070416)

julia> macro foo()
           Expr(:new, Foo)
       end
@foo (macro with 1 method)

julia> @foo()
ERROR: invalid struct allocation
Stacktrace:
 [1] top-level scope
   @ REPL[6]:1

```

Very annoying, since generated functions cause a lot more compilation overhead than macros.

---

<div class="post-metadata">

**Author:** ![HashBrown](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/hashbrown/32/43601_2.png) [@HashBrown](https://discourse.julialang.org/u/HashBrown)\
**Post date:** [November 22, 2022, 10:57pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/13 "2022-11-22T22:57:40Z")

</div>

Huh, interesting. Thanks!

---

<div class="post-metadata">

**Author:** ![Mason](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mason/32/2423_2.png) [@Mason](https://discourse.julialang.org/u/Mason)\
**Post date:** [November 22, 2022, 10:59pm UTC](https://discourse.julialang.org/t/extract-function-from-function-type/90651/14 "2022-11-22T22:59:53Z")

</div>

Also, I should note that using `new` in an inner constructor (i.e. the only place it’s really _meant_ to be used) works like how generated functions work, not like how `eval` or macros work:

```julia
julia> struct Foo
           x::Int
           Foo() = new()
       end

julia> Foo()
Foo(140463886091200)

```
