3

I thought of type fields as a more powerful syntax for type parameters, but a come across an example in which I can express my intent via the latter but not the former. The thing is that trait A compiles, while trait B does not.

trait Box[T]

trait A[T] extends (Box[T] => Box[T]) {
    override def apply(box: Box[T]): Box[T] = identity(box)
}

trait B extends (Box[T] => Box[T]) {
    type T
    override def apply(box: Box[T]): Box[T] = identity(box)
}

Is there a way to express what is expressed in A using type field as in B?

EDIT: Error message:

not found: type T
trait B extends (Box[T] => Box[T]) {
not found: type T
trait B extends (Box[T] => Box[T]) {
Pawel Batko
  • 761
  • 7
  • 19

1 Answers1

1

The override is useless in the current code, re-add if necessary.

Using an abstract type member will create concrete type to pass as a parameter with the placeholder syntax.

trait Box[T]

trait A[T] extends (Box[T] => Box[T]) {
    def apply(box: Box[T]): Box[T] = identity(box)
}

For B, using the type member T with Box[T] => Box[T] will:

  • force extending classes to adhere to the type bound.

  • create a concrete type to pass as a parameter

    trait B extends (Box[_] => Box[_]) { type T <: (Box[T] => Box[T]) def apply(box: Box[T]): Box[T] = identity(box) }

The compiler is telling you it can't find a type T to pass to the type constructor. In the case of B, you are trying to pass it before defining it.

The higherKind placeholder syntax will pass the inner type T to the type constructor.

This will be a good read.

Community
  • 1
  • 1
flavian
  • 28,161
  • 11
  • 65
  • 105