To avoid namespace pollution, I like to declare ADTs in hierarchies like so:
final case class Shape(geometry : Shape.Geometry, color : Shape.Color)
object Shape {
sealed trait Geometry
object Geometry {
case object Triangle extends Geometry
case object Rectangle extends Geometry
case object Circle extends Geometry
}
sealed trait Color
object Color {
case object Red extends Color
case object Green extends Color
case object Blue extends Color
}
}
The problem is that to construct a new object from this composition can be rather verbose, depends on how deep the hierarchy goes.
val redCircle = Shape(Shape.Geometry.Circle, Shape.Color.Red)
I can of course use import
to reduce the verbosity, but that recreates the namespace pollution I was trying to avoid.
I would like to propose a way to refer to an object/type in relation to the expected ADT argument. Using the example above:
val redCircle = Shape(.Circle, .Red)
In pattern matching:
val supportedShapes = shape match {
case Shape(.Triangle | .Rectangle, _) => true
case _ => false
}
In regards to syntax, if .Arg
is not obvious enough we can also consider a using a concept similar to paths: ./Triangle
or $.Trianlge
, or anything else that would make it more clear.
What do you think?