# Getting function's module by a MethodInstance

**URL:** <https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419>\
**Category:** Internals & Design\
**Created:** [January 15, 2021, 11:08pm UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419 "2021-01-15T23:08:03Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![ulysses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ulysses/32/665_2.png) [@ulysses](https://discourse.julialang.org/u/ulysses)\
**Post date:** [January 15, 2021, 11:08pm UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/1 "2021-01-15T23:08:03Z")

</div>

I’m looping over method instances in a module using @tim.holy’s marvelous `MethodAnalysis.jl`. I need to run `@code_typed` for those instances to extract some type information. For that I first resolve the function using `getfield` on `MethodInstance.def.module` and `MethodInstance.def.name`. The issue is that a method can be defined in other modules than the original function, so `MethodInstance.def.module` is not quite right.

Is there a way to get the module where the function was introduced using `MethodInstance` interface?

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [January 16, 2021, 10:32am UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/2 "2021-01-16T10:32:34Z")

</div>

I often do it that way, too. However, I’ve also noticed an alternative, which I sometimes remember to use:

```julia
julia> m = @which sum((1,2))
sum(x::Tuple{Any, Vararg{Any, N} where N}) in Base at tuple.jl:474

julia> ft = Base.unwrap_unionall(m.sig).parameters[1]
typeof(sum)

julia> ft.instance
sum (generic function with 14 methods)

```

I don’t remember whether the last line is always safe; maybe give it a try and let us know of any corrections you discover?

EDIT: and I’d be happy to have something like this wrapped up nicely and added to MethodAnalysis, if you want to submit a PR.

---

<div class="post-metadata">

**Author:** ![ulysses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ulysses/32/665_2.png) [@ulysses](https://discourse.julialang.org/u/ulysses)\
**Post date:** [January 19, 2021, 1:39am UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/3 "2021-01-19T01:39:07Z")

</div>

@tim.holy neat! There’s one problem with `instance` (as I figured running your approach on a bunch of instances): it’s not defined for constructors. E.g.

```julia
julia> h() = 1
julia> (@which h()).sig.parameters[1].instance                                 
h (generic function with 1 method)

julia> struct S end;
julia> (@which S()).sig.parameters[1].instance                                 
ERROR: UndefRefError: access to undefined reference                            
Stacktrace:                                                                    
 [1] getproperty(::Type{T} where T, ::Symbol) at ./Base.jl:28                  
 [2] top-level scope at REPL[95]:1   

```

(And the error looks a bit bizzare.) So, instead of `typeof(f)` we have `Type{SomeType}` at this spot.

This is not too hard to work around, though, assuming constructor’s function defined in the same module as the corresponding type. So, currently, I have the following to convert a method instance to a function:

```julia
instance_to_function(mi :: MethodInstance) = begin
    sig = Base.unwrap_unionall(mi.specTypes).types
    if sig[1] <: Function # typeof(func)
        sig[1].instance
    else # constructor
        getfield(
            parentmodule(sig[1].parameters[1]),
            mi.def.name)
    end
end

```

I’m yet to see how it works on a larger data set (it could reveal some more problems). But already this is good progress, thanks a lot!

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [January 19, 2021, 6:35am UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/4 "2021-01-19T06:35:48Z")

</div>

Nice catch! If `m` is a `Method`, does

```julia
typ = m.sig.parameters[1]
return typ <: Type ? typ.parameters[1] : typ.instance

```

always work?

---

<div class="post-metadata">

**Author:** ![ulysses](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ulysses/32/665_2.png) [@ulysses](https://discourse.julialang.org/u/ulysses)\
**Post date:** [January 25, 2021, 5:14pm UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/5 "2021-01-25T17:14:24Z")

</div>

Almost: `typ` can be a UnionAll, so after adding `Base.unwrap_unionall` to it it seems to work.

I also found that working with constructors (`typ <: Type`) is not very useful because of things like:

```julia
(::Type{T})(x::Number) where {T<:AbstractChar} = T(UInt32(x))

```

([base/char.jl#L48](https://github.com/JuliaLang/julia/blob/345ce78da9aba498e4d7c2dee5f11e6fbf4ddc7c/base/char.jl#L48))

My understanding is that without the actual value of `T` not much I can do with the signature I have (e.g. I use `code_typed` on the result but it fails for such signature). So I only analyze the case of `typ <: Function` right now.

---

<div class="post-metadata">

**Author:** ![tim.holy](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tim.holy/32/52_2.png) [@tim.holy](https://discourse.julialang.org/u/tim.holy)\
**Post date:** [January 25, 2021, 5:24pm UTC](https://discourse.julialang.org/t/getting-functions-module-by-a-methodinstance/53419/6 "2021-01-25T17:24:36Z")

</div>

I’ve played with this a bit in the meantime too. (Your question was useful since it made me think about this a bit more.) Here’s how SnoopCompile now deals with this:

[https://github.com/timholy/SnoopCompile.jl/blob/484231c34cb43f392f1d1aeeb0baad672c47b27a/src/parcel\_snoopi\_deep.jl#L1582-L1608](https://github.com/timholy/SnoopCompile.jl/blob/484231c34cb43f392f1d1aeeb0baad672c47b27a/src/parcel_snoopi_deep.jl#L1582-L1608)

`ft2f` (“function type to function”) is only used to print stuff to the REPL, so all that was needed was a good fallback for the case of a closure. And yes, just as you say I do have to `Base.unwrap_unionall` it before calling `ft2f`.
