L16. Case classes

/*
Clase in Scala
 */
class Point(a: Int, b: Int)  {
  def getA: Int = a
  def getB: Int = b
 
  def higher(p: Point): Boolean =
    a >= p.getA
 
  //string interpolation
  override def toString = s"(${a},${b})"
}
 
new Point(1,2)
new Point(2,1) == new Point(2,1)
 
trait TwoDimensionalObject{
  def distanceFromOrigin: Int
}
 
trait FTree
 
case class FNode (key: Int,
                  left: FTree,
                  right: FTree)
  extends FTree
  // o singura instanta a FEmpty
  // vezi singleton
case object FEmpty extends FTree
 
val t1 = FNode(3,
            FNode(2,FEmpty,
                    FEmpty),
            FNode(5, FEmpty,
                     FEmpty))
 
FEmpty == FEmpty
FNode(1,FEmpty,FEmpty) == FNode(1,FEmpty,FEmpty)
 
/* Cum putem introspecta arbori? */
 
def isEmpty(t: FTree): Boolean =
  t match {
    case FEmpty => true
    case _ => false
 
  }
 
def size (t: FTree): Int =
  t match {
    case FEmpty => 0
    case FNode(_,l,r) => 1 + size(l) + size(r)
  }
 
def contains(k: Int, t: FTree): Boolean =
  t match {
    case FEmpty => false
    case FNode(key,left,right) => k == key ||
                                  contains(k,left) ||
                                  contains(k,right)
  }
 
/* Putem defini operatiile pe arbori
SI ALTFEL?
 */
 
trait OOTree {
  def isEmpty: Boolean
  def size: Int
  def contains(k: Int): Boolean
}
 
case object OOEmpty extends OOTree{
 
  override def isEmpty:Boolean = true
  override def size:Int = 0
  override def contains(k: Int) = false
 
}
case class Leaf(key: Int) extends OOTree {
  override def isEmpty: Boolean = ???
  override def size: Int = ???
  override def contains(k: Int): Boolean = ???
}
case class OONode(key: Int,
                  left: OOTree,
                  right: OOTree)
            extends OOTree {
 
  override def isEmpty: Boolean = false
  override def size: Int = 1 + left.size + right.size
  override def contains(k: Int) =
    k == key || left.contains(k) || right.contains(k)
}
// Object-Oriented decomposition
trait Expr {
  def eval: Int
  def show: String
}
 
case class Val (i: Int) extends Expr {
  override def eval: Int = i
  override def show: String = s"${i}"
}
 
case class Var (s: String) extends Expr {
  override def eval: Int = ???
  override def show: String = s
}
 
case class Plus(e1: Expr, e2: Expr) extends Expr{
  override def eval: Int = e1.eval + e2.eval
 
  override def show: String = s"${e1.show} + ${e2.show}"
 
}
 
case class Mult(e1: Expr, e2: Expr) extends Expr{
  override def eval: Int = e1.eval * e2.eval
  override def show: String = s"${e1.show} * ${e2.show}"
 
}
 
Plus(Val(2),Mult(Val(3),Val(4))).eval