scalacontext-bound

Self referential View/Context bound


I am actually not clear whether the following were a view or context bound. Also not clear what the self referential aspect (re-referencing Model) is doing ;) :

abstract class Model[M <: Model[M]] extends Transformer {

An explanation on the meaning of "<: Model[M]" would be appreciated.


Solution

  • <: is neither a view nor context bound, but a type bound.

    Below is an extended example of how self referential type bounds can be used.

    The class ModelA uses a more restrictive type bound M <: ModelA[M] in order to make the method fooN work. ModelA2 can still extend ModelA[ModelA1], but not ModelA[ModelB1]. On the other hand, the class ModelB doesn't further restrict the type bound, so ModelB2 can extend ModelB[ModelA1]. The methods bar1 and bar2 restrict either the type bound or the parameter model, depending on the order in which the methods transform and bar are called on model.

    object Main extends App {
      val a: ModelA1 = foo(new ModelA1(), 2)
      val b: ModelA1 = foo(new ModelA2(), 3)
      val c: ModelB1 = bar1(new ModelB1())
      val d: ModelA1 = bar2(new ModelB2())
    
      def foo[M <: ModelA[M]](model: Model[M], n: Int): M = model.transform.fooN(n)
    
      def bar1[M <: ModelB[M]](model: Model[M]): M = model.transform.bar
    
      def bar2[M <: Model[M]](model: ModelB[M]): M = model.bar.transform
    }
    
    abstract class Model[M <: Model[M]] {
      def transform: M
    }
    
    abstract class ModelA[M <: ModelA[M]] extends Model[M] {
      def foo: M
    
      def fooN(n: Int): M = {
        var x: M = this.foo
        for (_ <- 2 to n)
          x = x.foo
        x
      }
    }
    
    abstract class ModelB[M <: Model[M]] extends Model[M] {
      def bar: M
    }
    
    class ModelA1 extends ModelA[ModelA1] {
      override def transform: ModelA1 = ???
      override def foo: ModelA1 = ???
    }
    
    class ModelA2 extends ModelA[ModelA1] {
      override def transform: ModelA1 = ???
      override def foo: ModelA1 = ???
    }
    
    class ModelB1 extends ModelB[ModelB1] {
      override def transform: ModelB1 = ???
      override def bar: ModelB1 = ???
    }
    
    class ModelB2 extends ModelB[ModelA1] {
      override def transform: ModelA1 = ???
      override def bar: ModelA1 = ???
    }