# Use of methods()

I would like to understand the use of `methods(function, types)`. Consider the following two invocations, whose results are not the same. This implies that the order in which the types are listed in the second argument impacts the return. Is this a bug or expected behavior? Thanks.

``````methods(+, [Int,Float])
methods(+, [Real, Int])
``````
``````methods(+, [Real,Int])
# 6 methods for generic function "+":
[1] +(x::BigInt, c::Union{Int16, Int32, Int64, Int8}) in Base.GMP at gmp.jl:527
[2] +(x::BigFloat, c::Union{Int16, Int32, Int64, Int8}) in Base.MPFR at mpfr.jl:394
[3] +(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:53
[4] +(a::Integer, b::Integer) in Base at int.jl:857
[5] +(x::T, y::T) where T<:Number in Base at promotion.jl:384
[6] +(x::Number, y::Number) in Base at promotion.jl:311
``````
``````methods(+, [Int,Real])
# 7 methods for generic function "+":
[1] +(x::T, y::T) where T<:Union{Int128, Int16, Int32, Int64, Int8, UInt128, UInt16, UInt32, UInt64, UInt8} in Base at int.jl:53
[2] +(c::Union{Int16, Int32, Int64, Int8}, x::BigInt) in Base.GMP at gmp.jl:528
[3] +(a::Integer, b::Integer) in Base at int.jl:857
[4] +(c::Union{Int16, Int32, Int64, Int8}, x::BigFloat) in Base.MPFR at mpfr.jl:398
[5] +(x::Integer, y::Ratios.SimpleRatio) in Ratios at /Users/erlebach/.julia/packages/Ratios/uRs4y/src/Ratios.jl:29
[6] +(x::T, y::T) where T<:Number in Base at promotion.jl:384
[7] +(x::Number, y::Number) in Base at promotion.jl:311
``````

Here are results when I invoke `methods` with a single type at a time:

``````methods(+,[Int])
# 1 method for generic function "+":
[1] +(x::Number) in Base at operators.jl:504

methods(+,[Real])
# 3 methods for generic function "+":
[1] +(x::Bool) in Base at bool.jl:93
[2] +(x::Rational) in Base at rational.jl:247
[3] +(x::Number) in Base at operators.jl:504

methods(+,[Int])
# 1 method for generic function "+":
[1] +(x::Number) in Base at operators.jl:504
``````

Given these results, I would expect that using two types would generate 4 results, not 6 or 7. There is clearly something I do not understand in how `methods` is supposed to work.

1 Like

Generally the order would of course matter â€” multiple dispatch does not care that `+` is commutative for certain domains, it may not be implemented in a way that reflects this.

1 Like

This dependence should be made clear in the documentation. It is hardly obvious. Lists of arguments are well defined, arenâ€™t they? Could somebody please provide a MWE to demonstrate why it is obvious that order is important? The documentation implies that if I use `types=[Int,Real]`, the methods should return all functions that have an argument that is either of type `Int` or of type `Real`.

I also do not understand why the total number of results with `types=[Int]` or `types=[Real]` adds up to less than the results using both types in a list. Perhaps this is expected behavior, but I do not understand it. There is no implication that the search only applies to the type of the first argument.

Here is a specific example. `methods(+,[Int,Real])` returns a list of 7 methods, including

``````[3] +(a::Integer, b::Integer) in Base at int.jl:857

``````

My question is: why isnâ€™t this method returned when invoking `methods(+,[Int])`?

I understand that this might be expected behavior, but I do not understand the behavior. Thanks.

I think you may be misinterpreting what `methods` does.

`methods(+, [Integer, Real])` returns all methods whose first argument is an `Integer` and whose second argument is a `Real`.

Lets assume everyone implements methods symmetricly, which as Tamas noted is required because Julia doesnâ€™t know that `+` is commutative.

Since there are more `Real` types than integer types, the number of returns is `num_integer_types * num_real_types`, which is not `N^2`.

There could also be weird performance reasons that something like `BigInt + Float64` is defined in a particular way but not `Float64 + BigInt`. I donâ€™t know if thatâ€™s true but I could imagine that scenario.

Also note that

``````julia> +(4)
4
``````

So someone has defined one-argument methods for `+` probably for some convenience reason.

2 Likes

Thank you, that makes sense. Note that if you invoke help in REPL, one gets

``````
methods(f, [types], [module])

Return the method table for f.

If types is specified, return an array of methods whose types match. If module is specified, return an array of methods defined in that module. A list of modules can also be specified as an array.

``````

There is no implication that types refer to a list of arguments in the same order as in the method definitions. Perhaps the definition could be amended?

Here is a MWE to test out some assumptions:

``````function Gordon(a::Real)
println(a)
end

methods(Gordon)
methods(Gordon, types=[Real])
``````

The two invocations of `methods` return:

``````methods(Gordon)

# 1 method for generic function "Gordon":
[1] Gordon(a::Real) in Main at /Users/erlebach/covid_modeling_julia/julia_code/sir-julia/SIRsims/gordon_julia_code/household_workplaces_leon/xxx.jl:395

``````

as expected, and

``````
methods(Gordon, types=[Real])
ERROR: MethodError: no method matching methods(::typeof(Gordon); types=DataType[Real])
Closest candidates are:
methods(::Any) at reflection.jl:905 got unsupported keyword argument "types"
methods(::Any, ::Union{Nothing, Module, AbstractArray{Module,N} where N}) at reflection.jl:905 got unsupported keyword argument "types"
methods(::Any, ::Any) at reflection.jl:879 got unsupported keyword argument "types"
...
Stacktrace:
[1] top-level scope at none:0

``````

which is not expected. This is probably the simplest case I can think of. In this case, my function is in the Global space and not within a `Module`. Should that make a difference? Thank you.

``````julia> methods(Gordon, [Real])
# 1 method for generic function "Gordon":
[1] Gordon(a::Real) in Main at REPL[1]:1

To edit a specific method, type the corresponding number into the REPL and press Ctrl+Q
``````

No where in the doc it mentions that `types` can be a keyword argument. This is not following the python convention.

You can see from the error that it is complaining about `methods` which has nothing to do with your function.

3 Likes

I have to agree with @erlebach in one thing, the documentation below is incredibly vague and unhelpful. Someone can only guess what it means, and then check by experiment.

Gordon Erlebacher
Chair, Department of Scientific Computing

Here is the source code for

methods()

. There is definitely a type argument, notwithstanding the implications of the error message.

â€śâ€ť" methods(f, [types], [module])
the method table for `f`.
If `types` is specified, return an array of methods whose types match.
If `module` is specified, return an array of methods defined in that module.
A list of modules can also be specified as an array.
!!! compat â€śJulia 1.4â€ť
At least Julia 1.4 is required for specifying a module.
â€śâ€ť"
function methods(@nospecialize(f), @nospecialize(t),
@nospecialize(mod::Union{Module,AbstractArray{Module},Nothing}=nothing))
if mod isa Module
mod = (mod,)
end
if isa(f, Core.Builtin)
throw(ArgumentError(â€śargument is not a generic functionâ€ť))
end
t = to_tuple_type(t)
world = typemax(UInt)
MethodList(Method[m[3] for m in _methods(f, t, -1, world) if mod === nothing || m[3].module in mod],
typeof(f).name.mt)
end

This is not python, having an argument named `a` does not mean you can call the function with `a=...`. Itâ€™s also not named `types` FWIWâ€¦

I appreciate all the replies. The command

``````methods(Gordon, [Real])
``````

works perfectly well. I must have had a typo, and no doubt, I used `types=` in a past thread, which was most assuredly, incorrect. Thank you for your patience with me.

1 Like