# 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,

``// Don'tsealed trait MyNumberfinal case class SomeNumber(n: Int) extends MyNumbercase object NoNumber extends MyNumber``

do this

``// Dosealed trait MyNumberobject MyNumber {  final case class SomeNumber(n: Int) extends MyNumber  case object NoNumber extends MyNumber}``

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.

``sealed trait MyNumberobject MyNumber {  final case class SomeNumber(n: Int) extends MyNumber  case object NoNumber extends MyNumber}sealed trait AnotherNumberobject AnotherNumber {  final case class SomeNumber(n: Int) extends MyNumber  case object NoNumber extends MyNumber}number match {  case MyNumber.SomeNumber(n) =>    // ...  case MyNumber.NoNumber =>    // ...}anotherNumber match {  case AnotherNumber.SomeNumber(n) =>    // ...  case AnotherNumber.NoNumber =>    // ...}``
``sealed trait ValidationErrorobject ValidationError {  final case class MissingField(name: String) extends ValidationError    final case class InvalidId(id: Long) extends ValidationError}``

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​

``sealed trait MyNumberobject MyNumber {  final case class SomeNumber(n: Int) extends MyNumber  final case class AnotherNumber(n: Int) extends MyNumber  case object NoNumber extends MyNumber  def someNumber(n: Int): MyNumber = SomeNumber(n)  def anotherNumber(n: Int): MyNumber = AnotherNumber(n)  def noNumber: MyNumber = NoNumber}``

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.

``val ns = List(MyNumber.SomeNumber(1), MyNumber.SomeNumber(5))// ns: List[MyNumber.SomeNumber] = List(SomeNumber(n = 1), SomeNumber(n = 5))``

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.

``val ns2 = List(MyNumber.SomeNumber(1), MyNumber.AnotherNumber(5))// ns2: List[Product with MyNumber with Serializable] = List(//   SomeNumber(n = 1),//   AnotherNumber(n = 5)// )``

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.

``// Use constructor methodsval ns3 = List(MyNumber.someNumber(1), MyNumber.someNumber(5), MyNumber.noNumber)// ns3: List[MyNumber] = List(SomeNumber(n = 1), SomeNumber(n = 5), NoNumber)``

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`: