Scala's sealed abstract vs abstract class - scala

What is the difference between sealed abstract and abstract Scala class?

The difference is that all subclasses of a sealed class (whether it's abstract or not) must be in the same file as the sealed class.

As answered, all directly inheriting subclasses of a sealed class (abstract or not) must be in the same file. A practical consequence of this is that the compiler can warn if the pattern match is incomplete. For instance:
sealed abstract class Tree
case class Node(left: Tree, right: Tree) extends Tree
case class Leaf[T](value: T) extends Tree
case object Empty extends Tree
def dps(t: Tree): Unit = t match {
case Node(left, right) => dps(left); dps(right)
case Leaf(x) => println("Leaf "+x)
// case Empty => println("Empty") // Compiler warns here
}
If the Tree is sealed, then the compiler warns unless that last line is uncommented.

Related

Is there any way to describe the type in scala 2 for case classes companion-objects of particular type?

Is there any way to describe the type in scala for case classes companion-objects of particular type ?
For example I have
trait SomeTrait
case class Foo() extends SomeTrait
case class Bar() extends SomeTrait
And I need to get common type for companion object of Foo and Bar
like [Foo.type & Bar.type]
You can create another trait that the companion objects will extend. If you need to make the companion objects pattern matchable, add case in front of them, and make the trait they extend sealed for exhaustivity reasons:
sealed trait SomeTrait
sealed trait AnotherTrait
case class Foo() extends SomeTrait
case class Bar() extends SomeTrait
case object Foo extends AnotherTrait
case object Bar extends AnotherTrait
And for example you can see which object you pattern matched with something like:
def methodName(x: AnotherTrait): String = x match {
case Foo => "it is Foo singleton"
case Bar => "it is Bar singleton"
}
println(methodName(Foo)) // it is Foo singleton

How should I implement scala interpreter for tuple?

I'm implementing scala interpreter and I have some problem.
To begin with, I want to implement tuple class
In my Value.scala, followed class exist:
case class TupleV(values: List[Type]) extends Value
Also, in my Expr.scala, followed class exist
case class TupleE(expressions: List[Type] extends Expr
Type is also in Expr.scala as followed:
sealed trait Type
case object IntT extends Type
case object BooleanT extends Type
case object TupleT extends Type
case object ListT extends Type
case object FunctionT extends Type
So, I implemented as followed:
case TupleE(values)=>TupleV(values)
but it says List[Expr] found, List[Value] is required. What is the problem in my code? what should I to to fix it?
Also I tried to implement in different way using ConsE and ConsV class which enable me to divide list into head and tail:
case class ConsE(head: Expr, tail: Expr) extends Expr//in Expr.scala
case class ConsV(head: Value, tail: Value) extends Value//in Value.scala
case ConsE(head, tail)=>ConsV(interp(head), interp(tail)//my implementation for ConsV interpreter&works well now
Using that, I tried
case TupleE(expression)=>expression match{
case ConsE(head, tail)=>ConsV(head, tail)
}
But it returns: "constructor cannot be instantiated to expected type" error for ConsE. How should I fix it?
Try to replace
case class TupleV(values: List[Type]) extends Value
case class TupleE(expressions: List[Type]) extends Expr
with
case class TupleV(values: List[Value]) extends Value
case class TupleE(expressions: List[Expr]) extends Expr
(Are those definitions given to you in an exercise or are they your own definitions that you can modify?)
Based on
case TupleE(values)=>TupleV(values)
you're writing interpreter
def interpret(expr: Expr): Value
i.e. continue what you started in How should I implement "add" interpreter in scala?
Then the definitions of TupleV, TupleE should be latter above. Former their definitions above make less sense to me.
Type is needed when you typecheck an Expr
def typecheck(expr: Expr): Type // or Option[Type]
Then you'll have one more hierarchy
case class TupleT(types: List[Type]) extends Type
So, I implemented as followed:
case TupleE(values)=>TupleV(values)
but it says List[Expr] found, List[Value] is required. What is the
problem in my code? what should I to to fix it?
This is irreproducible. The code compiles
https://scastie.scala-lang.org/KWlyFOYDRHOgN6UibVY1pw
Using that, I tried
case TupleE(expression)=>expression match{
case ConsE(head, tail)=>ConsV(head, tail)
}
But it returns: "constructor cannot be instantiated to expected type"
error for ConsE.
This error is clear: in TupleE(expression) expression has type List[Type], it can't match ConsE, it can match only ordinary scala List.

If case class inheritance is prohibited, how to represent this?

I am trying to create the case classes as explained in this article
sealed abstract case class Exp()
case class Literal(x:Int) extends Exp
case class Add(a:Exp, b:Exp) extends Exp
case class Sub(a:Exp,b:Exp) extends Exp
However, I am getting the following error in IntelliJ. I understand why it is prohibited (Why case-to-case inheritance is prohibited in Scala). What is the alternate way here?
Error:(2, 13) case class Literal has case ancestor A$A34.A$A34.Exp, but case-to-case inheritance is prohibited. To overcome this limitation, use extractors to pattern match on non-leaf nodes.
case class Literal(x:Int) extends Exp
^
Exp shouldn't use the case keyword. That is, a sealed abstract case class will rarely, if ever, make sense to use.
In this specific case, the only extra thing you get from sealed abstract case class Exp() is an auto-generated companion object Exp that has an unapply method. And this unapply method won't be very useful, because there isn't anything to extract from the generic Exp. That is, you only care about decomposing Add, Sub, etc.
This is just fine:
sealed abstract class Exp
case class Literal(x: Int) extends Exp
case class Add(a: Exp, b: Exp) extends Exp
case class Sub(a: Exp, b: Exp) extends Exp

Is it possible to use `case object` with a type parameter?

I'm currently learning Scala, and wanted to replicate this Haskell algebraic data type:
data Tree = Empty
| Leaf Int
| Node Tree Tree
This is what I came up with in Scala:
sealed trait Tree[T]
case class Empty[T]() extends Tree[T]
case class Leaf[T](value: T) extends Tree[T]
case class Node[T](left: Tree[T], right: Tree[T]) extends Tree[T]
However, someone told me that I should use a case object for Empty, which I suppose is true since it doesn't take parameters - but then again it does require a type parameter.
I tried the following but none of them compile:
case object Empty[T] extends Tree[T]
case object Empty extends Tree[T]
case object Empty extends Tree
So I'm wondering if there a way to use case object in this instance or not.
A singleton can't be generic because there's only one of them. If you want Tree to be covariant (i.e. Tree[Int] is a subtype of Tree[Any]), then you can define the types as
sealed trait Tree[+T]
case object Empty extends Tree[Nothing]
Otherwise, leave it as a case class.

Error : case class implementing parent's abstract method

I am learning scala, so bear with me if this a stupid question. I am experimenting with case classes and trying out the following:-
case class A {
def eval(x: Int): Boolean
}
case class B extends A
case class C extends A {
override def eval(x: Int): Boolean = true
// Compiler error is -
// Multiple markers at this line
// - Missing closing brace `}' assumed here
// - expected start of definition
}
Is it not possible for case classes to implement abstract methods?
A case class cannot inherit another case class (the compiler does a lot of magic). In scala, you would typically use a trait, so your code would look like:
trait A {
def eval(x: Int): Boolean
}
case class C() extends A {
override def eval(x: Int): Boolean = true
}
abstract case class is a contradiction in terms. It is not advisable to extend from a case class and by making a case class abstract you are forced to sub-class it to have an instantiable class.
The common pattern is an abstract class or trait as the base with one or more (often more than one) case classes always at the leafs of the inheritance tree.