Could a possible solution be to define a struct and a functor
struct TypedFunction{F<:Function, Tin, Tout}
f::F
end
TypedFunction(f::F, ::Type{Tin}, ::Type{Tout}) where {F, Tin, Tout} = TypedFunction{F, Tin, Tout}(f)
function (typedfun::TypedFunction{F, Tin, Tout})(x::Tin) where {F, Tin, Tout}
return convert(Tout, typedfun.f(x))
end
where Tin is the type of the input and Tout the type of the output and the functor guarantees that the input and the output are of the correct type.
In this way, if I define
mysin = TypedFunction(sin, Float64, Float64)
the compiler always know mysin only accepts arguments of the type Float64 and the returned value of mysin(2.0) is always a Float64. Correct?
P.S:: This discussion is related to this problem: Enforcing function signatures by both argument & return types