Algebraic Data Types

FILE : SealedDemo

In this workshop we will see how case classes and pattern matching give us new design possibilities.

When we create abstract sealed trait

sealed trait SomeAbstractType

Then we can only define subtypes in the same files which on the one side limits it extension but on the other side gives full information to compiler on what to expect in pattern matching. So for example if forgot to add one case then compiler will generate warning.

This construction is a lot more powerful that standard Java constructor because we can easily define different constructors.

And in case there are no arguments we can easily model this as singleton object.

final case class Implementation1(number: Int) extends SomeAbstractType
final case class OtherImplementation(text: String) extends SomeAbstractType
case object UniqueSubtype extends SomeAbstractType

The fact that compiler can verify if we handled all cases is important in context of function totality - in other words - if for every input parameter there is valid output value. If we miss case then of course we have a potential bug and this would be another definition of a bug

"bug - partial function treated as a total function"

example match {
    case Implementation1(number) => println(s"number=$number")
    case OtherImplementation(text) => println(s"tekst=$text")
    case UniqueSubtype => println("unique") //comment out and explain warning
}

Closed/Closed principle

Because all data variants are defined and sealed within one file then we can easily implement logic dispatch in abstract type. In the following example we can see part of the custom implementation of Option type which is an example of ADT in scala standard library.

sealed abstract class MyOption[A]{
  def getOrElse(other:A):A = this match {
    case MySome(a) => a
    case _ => other
  }
}
final case class MySome[A](a:A) extends MyOption[A]
final case class MyNone[A]() extends MyOption[A]

And now it looks like standard subtype polymorphism but we have full control beacuse of sealed hierarchy

val some:MyOption[Int] = MySome(1)
val result1=some.getOrElse(5)

EXERCISES

FILE : SealedTypesExercises

Exercise1 :

Implement HTTP statuses as Algebraic Data Types

  • in abstract trait implement method which return code according to implementation
  • in companion object implement utility method which return redirection when it is available

Exercise2

Implement Natural numbers as ADT. To do this you only need Zero and Next number so that 1 is Next(Zero) and 2 is Next(Next(Zero))

Exercise3

Implement part of custom Try which must have proper filter implementation. In this exercise you will have to add subtypes yourself.

results matching ""

    No results matching ""