I am defining few ADTs representing logic formulas. They all use i.e. And constructor, but then differ in what other constructors they use. I'd like to reuse case class definitions with a hope that I could reuse some code later. I'd like to do something like:
sealed trait Formula
sealed trait PositiveFormula
case class Not(sub) extends Formula
case class And(left, right) extends Formula, PositiveFormula
But this doesn't work for any single type for sub, left and right.
So I'd like to say:
sealed trait Formula
sealed trait PositiveFormula
case class Not[A](sub : A)
Not[Formula] extends Formula
case class And(left : A, right : A)
And[Formula] extends Formula
And[PositiveFormula] extends PositiveFormula
A few questions:
- Is anything like above possible and I just dont know syntax?
- Is there other solution to "reuse case class constructors" problem?
- What's your opinion on how useful this would be if possible?
In Scala parametric classes can't extend different parents for different type parameters (only parent's type parameter can vary).
It seems you want to have something like "
Not[T] extends T", "And[T] extends T" (pseudocode). See Scala : class[T] extends T?You can try
You can also introduce
FormulaLike, a common parent forFormulaandPositiveFormulaIs
PositiveFormulaaFormulaor not? Just in case, if so then you can makePositiveFormulaextendFormula(instead of introducingFormulaLike).Or maybe you can try to express your relations between types with type classes (inheritance can be too restrictive, composition should be preferred over inheritance)
https://www.baeldung.com/scala/type-classes (intro to type classes)
https://kubuszok.com/2018/implicits-type-classes-and-extension-methods-part-1/ (one more intro to type classes)
https://tpolecat.github.io/2015/04/29/f-bounds.html (type classes and F-bounds)
https://github.com/milessabin/shapeless/blob/main/core/shared/src/main/scala/shapeless/ops/nat.scala (example of type-level calculations with type classes)
You can have hierarchy of classes (nodes) extending
Formulaand mark some of the nodes as belonging to the type classIsPositiveor use phantom types with type classes
or use phantom types keeping type classes only for type-level calculations
or use phantom types without type classes
FormulaandPositiveFormulaare abstract types rather than traits to avoidClassCastException.