Specification of the signature of a Function in a struct

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