Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unable to import a case class in an abstract class

Tags:

scala

I want to run the class Expr below. I've taken this code from http://andymaleh.blogspot.ie/2008/04/scalas-pattern-matching-visitor-pattern.html

Here is what I am trying :

import Expr.Sum

object Main {

    def main(args:Array[String]) {

      var expr1 = new Sum(new Num(1), new Prod(new Num(2), new Num(3)))
      print(expr1)
  }

}

abstract class Expr {

  case class Num(n: Int) extends Expr
  case class Sum(l: Expr , r: Expr) extends Expr
  case class Prod(l: Expr, r: Expr) extends Expr

  def evalExpr(e: Expr): Int = e match {
    case Num(n) => n
    case Sum(l, r) => evalExpr(l) + evalExpr(r)
    case Prod(l, r) => evalExpr(l) * evalExpr(r)
  }

  def printExpr(e: Expr) : Unit = e match {
    case Num(n) => print(" " + n + " ")
    case Sum(l, r) => printExpr(l); print("+"); printExpr(r)
    case Prod(l, r) => printExpr(l); print("x"); printExpr(r)
  }

}

But line

import Expr.Sum

is causing a compile time error : 'not found: object Expr' . How can I import the class Expr ?

like image 362
user701254 Avatar asked Dec 21 '22 13:12

user701254


2 Answers

You can only import members of instances. So your code would be:

object Main {
    def main(args:Array[String]) {
      val expr = new Expr {} // now we have a instance.

      import expr._
      var expr1 = new Sum(new Num(1), new Prod(new Num(2), new Num(3)))
      print(expr1)
  }
}

A simple example explains why you can't import non-instances members:

class A(val x:Int) {
  object Print { def print = println(x) }
}

If you could import A.Print, which value would be bound to x? Now if we do:

val a = new A(5); // we have a value bound to x.
import a._
Print.print

This is one reason. The other reason that new A(5).Print != new A(5).Print, not only in equality, but also in type: val (a1, a2) = (new A(5), new A(5)); implicitly[a1.Print <:< a2.Print] wouldn't compile. This is what Scala calls path-dependent types.

like image 64
pedrofurla Avatar answered Jan 05 '23 17:01

pedrofurla


Moving the case classes out of the abstract class gets it to compile. They are also in the same scope in this case so there is nothing to import.

Also note that an import error isn't applicable here since Main and Expr are defined in the same package. i.e. the default package.

object Main {    
    def main(args:Array[String]) {

      var expr1 = new Sum(new Num(1), new Prod(new Num(2), new Num(3)))
      print(expr1)
  }
}

abstract class Expr {
}

case class Num(n: Int) extends Expr
case class Sum(l: Expr , r: Expr) extends Expr
case class Prod(l: Expr, r: Expr) extends Expr

def evalExpr(e: Expr): Int = e match {
  case Num(n) => n
  case Sum(l, r) => evalExpr(l) + evalExpr(r)
  case Prod(l, r) => evalExpr(l) * evalExpr(r)
}

def printExpr(e: Expr) : Unit = e match {
  case Num(n) => print(" " + n + " ")
  case Sum(l, r) => printExpr(l); print("+"); printExpr(r)
  case Prod(l, r) => printExpr(l); print("x"); printExpr(r)
}

Running this gives:

scala>Main.main(Array[String]())
Sum(Num(1),Prod(Num(2),Num(3))) 
like image 36
Brian Avatar answered Jan 05 '23 19:01

Brian