scalaself-typetype-projection

Use type member as self-type


I'm having a problem with a recursive self-type that should correspond to a type member:

trait Elem { me =>
  type Peer

  import me.{Peer => Peer0}

  type This <: Elem { type Peer = Peer0 }

  def mkCopy(): This
}

Now I want to define a convenient trait:

trait ImmutableImpl extends Elem {
  _ : This =>

  def mkCopy(): This = this
}

This doesn't work, because "error: not found: type This" :(

Next attempt:

trait ImmutableImpl[Repr] extends Elem {
  _ : Repr =>

  type This = Repr

  def mkCopy(): This = this
}

This fails with "Error: overriding type This ... This has incompatible type".

I can do only this abomination:

trait ImmutableImpl[Peer0, Repr <: Elem { type Peer = Peer0 }] extends Elem {
  _ : Repr =>

  type Peer = Peer0
  type This = Repr

  override def mkCopy(): This = this
}

class IntElem extends ImmutableImpl[Int, IntElem]

In the real case I have more type members, so that makes this last approach useless, as it's much more boiler plate that implementing the mkCopy by hand each time.

Any ideas?


Solution

  • My workaround is to relax the refinement on This, as it appears to not be required in my API in the end:

    trait Elem { me =>
      type Peer
    
      // import me.{Peer => Peer0}
    
      type This <: Elem // { type Peer = Peer0 }
    
      def mkCopy(): This
    }
    
    trait ImmutableImpl[Repr <: Elem] extends Elem {
      _ : Repr =>
    
      override type This = Repr
    
      def mkCopy(): This = this
    }
    
    class IntElem extends ImmutableImpl[IntElem] {
      type Peer = Int
    }