Algebraic Data Type (ADT)
Algebraic Data Type (ADT)
Define Data in Companion Object
When defining an ADT, define the data in the companion object.
So instead of writing ADT like this,
do this
With this, naming conflict in data can be avoided and the companion object can be a namespace so that it is easy to access all the available data constructors in each ADT.
Since MissingField
belongs to ValidationError
, it can be used as
ValidationError.MissingField
so no need to repeat Error
in its data name like MissingFieldError
.
It's the same in InvalidId
.
Use Constructor Methods
To save time to create all constructor methods, use IDE's auto-complete templates. For IntelliJ IDEA, try this one at this blog post. The link to download can be found at https://blog.kevinlee.io/2019/10/01/save-your-time-on-algebraic-data-type-creation-in-scala/#get-the-template-settings (The demo video of the template).
Why?
There can be unwanted types created if data constructors are used. This is an issue with Scala as there is no better way to keep the data hidden and not expose as a type.
As you can see, you've got List[MyNumber.SomeNumber]
instead of List[MyNumber]
If you mix more than one data class, you get some weirdly inferred type like this.
As you can see, it's not List[MyNumber]
but Product with MyNumber with Serializable
.
This is because Scala compiler infers the common type of MyNumber.SomeNumber
and MyNumber.AnotherNumber
.
Since case class
is a Product
and also Serializable
,
these are the common types of the both case classes along with MyNumber
.
To avoid all these issues, you can use the constructor methods like this.
Now the type is List[MyNumber]
as you wanted.
For, Option
and Either
use data constructors provided by FP libraries like Scalaz and Cats.
More about Option
and Either
: