Help to remove type instability

Hi!

I am trying to create a signal system for my package TextUserInterfaces.jl.

As of now, I have the following kind of structure defining a signal that will be emitted when return is pressed:

mutable struct Object
    on_return_pressed::Function
    vargs_on_return_pressed::Tuple
end

Then, the user can connect a function to be executed with this signal using:

obj = Object( ()->nothing, tuple() )
func(a,b) = a+b
obj.on_return_pressed = func
obj.vargs_on_return_pressed = (1,2)

It is working fine. The problem is that when I call on_return_pressed I have a type instability. Can anyone help me to remove it? See the following MWE:

julia> mutable struct Object
           on_return_pressed::Function
           vargs_on_return_pressed::Tuple
       end

julia> function test()
           obj = Object( ()->nothing, tuple() )
           func(a,b) = a+b
           obj.on_return_pressed = func
           obj.vargs_on_return_pressed = (1,2)
           return obj.on_return_pressed(obj.vargs_on_return_pressed...)
       end
test (generic function with 1 method)

julia> @code_warntype test()
Variables
  #self#::Core.Compiler.Const(test, false)
  #3::var"#3#4"
  obj::Object
  func::var"#func#5"

Body::Any
1 ─       (#3 = %new(Main.:(var"#3#4")))
│   %2  = #3::Core.Compiler.Const(var"#3#4"(), false)
│   %3  = Main.tuple()::Core.Compiler.Const((), false)
│         (obj = Main.Object(%2, %3))
│         (func = %new(Main.:(var"#func#5")))
│         Base.setproperty!(obj, :on_return_pressed, func)
│   %7  = Core.tuple(1, 2)::Core.Compiler.Const((1, 2), false)
│         Base.setproperty!(obj, :vargs_on_return_pressed, %7)
│   %9  = Base.getproperty(obj, :on_return_pressed)::Function
│   %10 = Base.getproperty(obj, :vargs_on_return_pressed)::Tuple
│   %11 = Core._apply_iterate(Base.iterate, %9, %10)::Any
└──       return %11

You probably need to use a type parameter for the field holding the function as Function is abstract. Same goes for Tuple:

mutable struct Object{F<:Function, T<:Tuple}
    on_return_pressed::F
    vargs_on_return_pressed::T
end

Edit: But note, that with this approach compile time will go up as new JITting needs to happen for all different F and T. This application seems like it might be better off with a type-instability.

1 Like

Thanks! The other problem is that the user will need to have the signal function ready when the object is created. I think I can add a macro to annotate the function with the return type in case the user wants type instability.

A halfway measure would be to only specialize the Object on function type, as this is probably more important.

But, in this case, the user will not be able to change the signal (the function) after the object is created, right?

Correct.