Enforcing function signatures by both argument & return types

Will this work instead:

julia> struct MyFunctor{T1,T2,S} end

julia> MyFunctor{T1,T2,S}(arg1::T1, arg2::T2) where {T1, T2, S} = S(arg1+arg2)

julia> myfunc = MyFunctor{Int,Int,Float64}
MyFunctor{Int64,Int64,Float64}

julia> myfunc(1,3)
4.0

julia> myfunc(1,3.)
ERROR: MethodError: no method matching MyFunctor{Int64,Int64,Float64}(::Int64, ::Float64)

julia> g(f::Type{MyFunctor{Int,Int,Float64}}, a::Int, b::Int) = f(a,b)::Float64
g (generic function with 1 method)

julia> g(MyFunctor{Int,Int,Float64}, 1, 2)
3.0

julia> g(MyFunctor{Int,Int,Int}, 1, 2)
ERROR: MethodError: no method matching g(::Type{MyFunctor{Int64,Int64,Int64}}, ::Int64, ::Int64)
Closest candidates are:
  g(::Type{MyFunctor{Int64,Int64,Float64}}, ::Int64, ::Int64) at REPL[6]:1

This is like defining your own function type and making methods for it, then dispatching on the argument and return types of the function.

You can also have an abstract type IntIntFloat64 and use f::Type{<:IntIntFloat64} instead when defining g, like this:

julia> abstract type TwoArgOneRetFunctor{T1, T2, S} end

julia> const IntIntFloat64 = TwoArgOneRetFunctor{Int,Int,Float64}
TwoArgOneRetFunctor{Int64,Int64,Float64}

julia> struct f1 <: IntIntFloat64 end

julia> f1(arg1::Int, arg2::Int) = Float64(arg1+arg2)
f1

julia> g(f::Type{<:IntIntFloat64}, a::Int, b::Int) = f(a,b)::Float64
g (generic function with 2 methods)

julia> g(f1, 1, 2)
3.0

julia> struct f2 <: IntIntFloat64 end

julia> f2(arg1::Int, arg2::Int) = Float64(arg1*arg2)
f2

julia> g(f2, 3, 2)
6.0
5 Likes