Hi. I’ve got a struct that has a Function as a field. I’d like to specify the signature of this function in some way, for example:
struct Mapper
lower::Float64
upper::Float64
mapFunc::Function{Float64 -> Float64}
end
Is there any way of doing this?
Thanks.
Depends on what you want to do with it, but generally not. If you are interested in the rationale and alternative solutions, search the discussions for “arrow types”.
If you just want concrete types, the idiomatic solution is
struct Mapper{T}
lower::Float64
upper::Float64
mapFunc::T
end
Thanks! I’ll look into arrow types, as you suggest.
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
Actually, it does not.
For direct use, it works:
julia> @code_warntype(mysin(1.5))
Variables
typedfun::Core.Compiler.Const(TypedFunction{typeof(sin),Float64,Float64}(sin), false)
x::Float64
Body::Float64
1 ─ %1 = $(Expr(:static_parameter, 3))::Core.Compiler.Const(Float64, false)
│ %2 = Base.getproperty(typedfun, :f)::Core.Compiler.Const(sin, false)
│ %3 = (%2)(x)::Float64
│ %4 = Main.convert(%1, %3)::Float64
└── return %4
sin
works for indirect use:
julia> function testsin(x::Float64)
y = sin(x)
return y
end
testsin (generic function with 1 method)
julia> @code_warntype(testsin(0.5))
Variables
#self#::Core.Compiler.Const(testsin, false)
x::Float64
y::Float64
Body::Float64
1 ─ (y = Main.sin(x))
└── return y
here is mysin
julia> function testmysin(x::Float64)
y = mysin(x)
return y
end
testmysin (generic function with 1 method)
julia> @code_warntype(testmysin(0.5))
Variables
#self#::Core.Compiler.Const(testmysin, false)
x::Float64
y::Any
Body::Any
1 ─ (y = Main.mysin(x))
└── return y
Thanks for the feedback! That is interesting. But if I declare mysin
as a const
const mysin = TypedFunction(sin, Float64, Float64)
function testmysin(x::Float64)
y = mysin(x)
return y
end
then it seems to work fine
julia> @code_warntype(testmysin(0.5))
Body::Float64
1 ─ %1 = invoke sin(_2::Float64)::Float64
└── return %1
I am not sure I understand why it works in this case…
const values propagate well