Alexander Arendar Alexander Arendar - 2 months ago 13
Scala Question

Two seemingly identical strings behave differently

Look at the following code which compiles nicely:

trait ParserError
trait Parser[+A]{
def run[A](input:A):Either[ParserError, A]
}

object Parser{
case object ParserErrorImpl extends ParserError

def string(s:String):Parser[String] = new Parser[String]{
def run[String](input:String) = {
if(input == s) Right(input) else Left(ParserErrorImpl)
}
}
}

object Runner{
import Parser._
def main(args:Array[String]):Unit={
println(string("aaa").run("aaa"))
}
}


When I change
Right(input)
to
Right(s)
it brings a compilation error:

Error:(13, 58) type mismatch;
found : s.type (with underlying type String)
required: String
def run[String](input:String) = if(input == s) Right(s) else Left(ParserErrorImpl)
^


Could you explain why this happens since it is not completely clear to me?

Answer

You are shadowing your type parameter A by (re)defining it in your run method. Make trait Parser parameterized by type A and use that type as the run method's parameter type.

Here's the fixed version:

trait ParserError
trait Parser[A]{
  def run(input:A):Either[ParserError, A] // <-- not run[A] !!!
}

object Parser{
  case object ParserErrorImpl extends ParserError

  def string(s:String):Parser[String] = new Parser[String]{
    def run(input:String) = {
      if(input == s) Right(input) else Left(ParserErrorImpl)
    }
  }
}

Note that type parameter A can no longer be covariant for Parser since it occurs in contravariant position (function parameters are contravariant positions, while return types are covariant).

Comments