Home > Blockchain >  Scala interprets _ param as Any => [Any]
Scala interprets _ param as Any => [Any]

Time:05-21

I have an enum defined as follows

enum Operator[T](val expr: String, val tag: T):

  case Plus(override val tag: T) extends Operator(" ", tag)
  case Minus(override val tag: T) extends Operator("-", tag)
  case Multiply(override val tag: T) extends Operator("*", tag)

Next is a function call that checks whether the passed list of operators starts with a certain operator or not

def extract[A](expect: Operator[A], operators: List[Operator[A]]): Either[Error[A], (Operator[A], List[Operator[A]])] =
  operators match {
    case `expect` :: tail  => Right(expect, operators.tail)
    case _ =>
      expect match {
        case Plus(_)       => Left(Error.ExpectPlus(operators))
        case Minus(_)      => Left(Error.ExpectMinus(operators))
        case Multiply(_)   => Left(Error.ExpectMultiply(operators))
      }
  }

But when I call the function with the following parameter, I get the error as below

extract(Plus(_), operators)
^^^^^^^^^^^^^^^
[error]     |                               Found:    Any => Operator[Any]
[error]     |                               Required: Operator[Any]

Can anyone help me explain why using _ as a parameter is interpreted as Any => [Any], is there any way to solve this error?

Here is the snippet: https://scastie.scala-lang.org/XLrcrUBvSneJs60w87k43A

CodePudding user response:

What you wrote is the same as below:

extract(x => Plus(x), operators)
// Same as:
extract(Plus(_), operators)

Meaning Plus(_) defines a function, which is not what extract expects.

CodePudding user response:

This is actually a complement to @Luis Miguel Mejía Suárez's comment and @Gaël J's answer. As stated earlier in the comments and answers, you're actually passing a function, not an Operator instance to your extract function. I think what you intended to do, was to use a wildcard for the tag in Plus (of course this is not a wildcard, this results in a function). And based on these assumptions, I think what you're looking for is type matching. So this needs a little bit of refactoring, now this code is written in Scala 2, but the concepts should be pretty much applicable to Scala 3 as well:

// I have defined the Operator as sealed abstract class earlier, and all the subtypes

sealed trait Err[OP <: Operator[_]]
object Err {
  def apply[T <: Operator[_]]: Err[T] = new Err[T] {} // In Scala3 you can easily do type matching here
}

import scala.reflect.ClassTag

def extract[A, OperatorType <: Operator[A] : ClassTag](operators: List[Operator[A]]): Either[Err[OperatorType], (Operator[A], List[Operator[A]])] = {
  operators match {
    case (head : OperatorType) :: tail =>
      Right(head, tail)
    case _ => Left(Err[OperatorType])
  }
}

val ops: List[Operator[Int]] = List(Plus(2), Minus(4), Multiply(7))
val shouldFail = extract[Int, Minus[Int]](ops) // fails since first element is not of type Minus
val shouldSucceed = extract[Int, Plus[Int]](ops) // succeeds

On scastie.

  • Related