Virtual class plugin pattern

I’ve been trying to implement a plugin feature for updating mutable vals in a class.

I get a compile error in class xxx on method do_update, telling me Self type cannot escape its class.

I would have thought that constraining the yyy virtual method argument with a 'xxx type might have kept the compiler happy.

Could anyone suggest a possible workaround?

class xxx (plugin', a) = object (self:'xxx)

    val mutable a: float = a
    method a = a
    method set_a a' = a <- a'

    val mutable plugin:yyy = plugin'
    method set_plugin plugin' = plugin <- plugin'

    method do_update = plugin#do_update self

  end

  and virtual yyy = object

    method virtual do_update: (xxx:'xxx -> unit)

  end

  class test_yyy_1 = object
    inherit yyy

    method do_update updatee =
      updatee#set_a (updatee#a +. 1.)

  end

  class test_yyy_2 = object
    inherit yyy

    method do_update updatee =
      updatee#set_a (updatee#a +. 2.)

  end

  let () =
    let my_test_yyy_1 = new test_yyy_1 in
    let my_xxx = new xxx (my_test_yyy_1,1.) in
    my_xxx#do_update;
    Printf.printf "%f\n" my_xxx#a;
    let my_test_yyy_2 = new test_yyy_2 in
    my_xxx#set_plugin my_test_yyy_2;
    my_xxx#do_update;
    Printf.printf "%f\n" my_xxx#a

You can get around the issue by coercing self to the type of the class before passing it to do_update. Then you need to be careful to use real types, not type variables (no ' before the name).
Here is one version that compiles:

class xxx (plugin', a) = object (self)

    val mutable a: float = a
    method a = a
    method set_a a' = a <- a'

    val mutable plugin:yyy = plugin'
    method set_plugin plugin' = plugin <- plugin'

    method do_update = plugin#do_update (self :> xxx)

  end

  and virtual yyy = object

    method virtual do_update: (xxx -> unit)

  end
1 Like

Thanks! I started writing with classes at the beginning of the week and just couldn’t figure this one out. Thanks again