object Xxx
defines a value named Xxx
. It’s type is Xxx.type
. Conceptually object Xxx extends Yyy with Zzz {}
is very similar to lazy val Xxx = new Yyy with Zzz {}
. Also, uppercase identifiers in patterns are treated as constants to match against.
Top level lazy vals are not allowed, so I’ll wrap NodeType
subtypes in object NodeType
. After that adjustment following code still doesn’t compile:
package questions
import questions.NodeType._
sealed trait NodeType {
def &&(anotherNode: NodeType): NodeType = (this, anotherNode) match {
case (a, b) if a == b => a
case (a: PureType, b: RightNodeType) => PureType
case _ => this
}
}
object NodeType {
object PureType extends NodeType
object RightNodeType extends NodeType
object LeftNodeType extends NodeType
}
That is because PureType
and RightNodeType
are values, not types, If PureType
was a type, then PureType
wouldn’t be allowed to be used as a value at the right side of a case. You need to add .type
suffix to extract type from value. Therefore the code will look like that:
package questions
import questions.NodeType._
sealed trait NodeType {
def &&(anotherNode: NodeType): NodeType = (this, anotherNode) match {
case (a, b) if a == b => a
case (a: PureType.type, b: RightNodeType.type) => PureType
case _ => this
}
}
object NodeType {
object PureType extends NodeType
object RightNodeType extends NodeType
object LeftNodeType extends NodeType
}
If we change object
to lazy val
then the &&
method still compile fine (and probably would work correctly as I’ve assigned new anonymous class to every lazy val):
package questions
import questions.NodeType._
sealed trait NodeType {
def &&(anotherNode: NodeType): NodeType = (this, anotherNode) match {
case (a, b) if a == b => a
case (a: PureType.type, b: RightNodeType.type) => PureType
case _ => this
}
}
object NodeType {
lazy val PureType = new NodeType {}
lazy val RightNodeType = new NodeType {}
lazy val LeftNodeType = new NodeType {}
}
Note that code below compiles because PureType
and RightNodeType
were used as values (they are values, so that’s OK) during comparison.
package questions
import questions.NodeType._
sealed trait NodeType {
def &&(anotherNode: NodeType): NodeType = (this, anotherNode) match {
case (a, b) if a == b => a
case (a, b) if a == PureType && b == RightNodeType => PureType
case _ => this
}
}
object NodeType {
object PureType extends NodeType
object RightNodeType extends NodeType
object LeftNodeType extends NodeType
}
You can use the fact that uppercase identifiers are treated as constants and remove explicit comparisons ending with following code:
package questions
import questions.NodeType._
sealed trait NodeType {
def &&(anotherNode: NodeType): NodeType = (this, anotherNode) match {
case (a, b) if a == b => a
case (PureType, RightNodeType) => PureType
case _ => this
}
}
object NodeType {
object PureType extends NodeType
object RightNodeType extends NodeType
object LeftNodeType extends NodeType
}
As before, you can replace object
with anonymous class assigned to lazy val
and code will work the same way.