Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does scalac not believe that a method does not fit the required type signature?

Tags:

types

scala

Why does this not compile?
The error given is class SomeElement needs to be abstract, since method eval in trait Element of type [T <: Typed]=> scala.util.Try[T] is not defined

I cannot understand why the method eval defined on SomeElement does not satisfy the type constraints.

As I understand it, eval should return something wrapped in a Try which subclasses Typed. Try is covariant in its type parameter. The implementation of eval in SomeElement returns a NumberLike, and NumberLike subclasses Typed. So what's gone wrong?

import scala.util.Try

trait Element {
   def eval[T <: Typed]: Try[T]
}

trait Typed

case class NumberLike(n: Long) extends Typed

case class SomeElement(n: Long) extends Element {
  def eval = Try {
    NumberLike(n)
  }
}

object app extends Application {
  println (SomeElement(5).eval)
}

Trying to add an explicit type parameter to eval in SomeElement doesn't help either:

case class SomeElement(n: Long) extends Element {
  def eval[NumberLike] = Try {
    NumberLike(n)
  }
}

Changing the defintion of SomeElement to the above gives:

  found   : <empty>.NumberLike
  required: NumberLike(in method eval)
    NumberLike(n)

EDIT I would really like to know why this doesn't compile. Workarounds for the problem are helpful, but I really want to know what's going on here.

like image 942
Squidly Avatar asked Aug 28 '14 14:08

Squidly


1 Answers

The type parameter T being defined on the function, not on the enclosing type Element, it can't be 'erased' by inheritance and must be kept on the overriding function (http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-objects.html#class-members).

Moving the type parameter to Element definition make it work as following.

trait Element[T <: Typed] {
   def eval: Try[T]
}

trait Typed

case class NumberLike(n: Long) extends Typed

case class SomeElement(n: Long) extends Element[NumberLike] {
  def eval = Try {
    NumberLike(n)
  }
}

Or using a type member:

trait Element {
   type T <: Typed
   def eval: Try[T]
}

trait Typed

case class SomeElement(n: Long) extends Element {
  type T = NumberLike
  def eval = Try {
    NumberLike(n)
  }
}
like image 170
cchantep Avatar answered Sep 20 '22 12:09

cchantep