1
votes

I'm learning Scala and the following simple program got me stuck:

class ObjectPrinter[T <: AnyVal](x: T) {
  def print(t: T) = { // <--- error here
    case Is(i) => println("Integer: " + i)
    case Ds(d) => println("Double: " + d)
    case _ => println("Default")
  }

  case class Is(i : Int) extends ObjectPrinter[Int](i);
  case class Ds(d: Double) extends ObjectPrinter[Double](d);
}

The error message is the following:

Missing type parameter for expanded function. The argument type of an anonymous function must be fully known. Expected type was: ?

The message is completely unclear to me. What do they mean, missing type parameter? I thought the type parameter follows after the case, like Is(i). What function is expanded?

UPD: I want to return a function depending on the type of the argument passed in as a parameter.

2
def print(t: T) = t match { ... } ? Currently your method returns an anonymous function, and t is not used.Victor Moroz

2 Answers

4
votes
{
  case Is(i) => println("Integer: " + i)
  case Ds(d) => println("Double: " + d)
  case _ => println("Default")
}

is short for

y => y match {
  case Is(i) => println("Integer: " + i)
  case Ds(d) => println("Double: " + d)
  case _ => println("Default")
}

(that's the expanded function the error is talking about. But the compiler has no way to tell what do you want y's type to be.

If this is what you want, the simplest way to specify the type would be

(_: SomeType) match {
  case Is(i) => println("Integer: " + i)
  case Ds(d) => println("Double: " + d)
  case _ => println("Default")
}

But this looks quite strange: you are using neither x nor t there.

2
votes

I would implement it through typeclass

case class ObjectPrinter[T <: AnyVal](x: T)

object ObjectPrinter {
  implicit val printInt = new Print[Int] {
    override def print(t: ObjectPrinter[Int]): Unit = println("Integer: " + t.x)
  }

  implicit val printDouble = new Print[Double] {
    override def print(t: ObjectPrinter[Double]): Unit = println("Double: " + t.x)
  }

  def print[T <: AnyVal](t: ObjectPrinter[T])(implicit print: Print[T]) = {
    print.print(t)
  }
}

trait Print[T <: AnyVal] {
  def print(t: ObjectPrinter[T]): Unit
}

Alternatively, this one - compiles

class ObjectPrinter[T <: AnyVal](x: T) {
  def print(t: T): Unit = t match { 
    case i: Int => println("Integer: " + i)
    case d: Double => println("Double: " + d)
    case _ => println("Default")
  }

  case class Is(i : Int) extends ObjectPrinter[Int](i);
  case class Ds(d: Double) extends ObjectPrinter[Double](d);
}

(though I do not see any usecase how you would use print, i.e. why do you enforce t and x be the same type)

May be you meant to have such implementation:

class ObjectPrinter[T <: AnyVal](x: T) 

object ObjectPrinter {
  def print[T <: AnyVal](op: ObjectPrinter[T]): Unit = op match { // <--- error here
    case Is(i: Int) => println("Integer: " + i)
    case Ds(d: Double) => println("Double: " + d)
    case _ => println("Default")
  }

}

case class Is(i : Int) extends ObjectPrinter[Int](i)
case class Ds(d: Double) extends ObjectPrinter[Double](d)

object Test extends App {
  ObjectPrinter.print(Is(5))
}