Save Your Time on Algebraic Data Type (ADT) Creation in Scala

Why ADT?

(If you want to get straight to the solution, just click this.)
If you do Functional Programming in Scala, you probably write lots of Algebraic Data Types (ADT). If you’re not sure what it is or why we use or what benefits it offers, here is a good blog post written by Charles O’farrell about The Expression Tradeoff which can give you a good idea of why we use ADT. I strongly recommend reading it.

Writing ADTs in Scala can be annoying as it requires to write data constructor methods the reason of which is explained in The Expression Tradeoff. Again please read it first.

Another Issue with ADT without Constructor Methods

Another reason why constructor methods are better is that it can avoid unwanted type inference.

For instance, if you have an ADT like this.

sealed trait MyType

object MyType {
  final case class Foo(n: Int) extends MyType
  final case object Bar extends MyType
}

and put the data in a List

List(MyType.Foo(1), MyType.Bar) // List[Product with MyType with Serializable]

The inferred type of the List is not List[MyType]. It’s List[Product with MyType with Serializable] as Scala compiler tries to infer the common types of the given case class and case object. Both case class and case object are Product as well as Serializable and that’s why its inferred type is List[Product with MyType with Serializable].

To fix this issue, you can make MyType Product with Serializable.

sealed trait MyType extends Product with Serializable
List(MyType.Foo(1), MyType.Bar) // List[MyType]

However, this doesn’t still solve the issue with exposing data (case class and case object) not type (sealed trait). So it’s better to use constructor methods just like the “The Expression Tradeoff” says

sealed trait MyType

object MyType {
  final case class Foo(n: Int) extends MyType
  final case object Bar extends MyType

  def foo(n: Int): MyType = Foo(n)
  def bar: MyType = Bar
}

Although it’s a better way, now you have some boilerplate code in every ADT creation.

(NOTE: The issue makes us use constructor methods is solved in Scala 3 as it has a proper ADT support with enum.)

Save Your Time on ADT Creation with IntelliJ IDEA Live Templates

So what I want to show you is a way to save time on writing ADTs in Scala using IntelliJ IDEA’s live templates.

I certainly don’t like to spend time on writing that boilerplate code so created an IntelliJ IDEA live template which can create data constructor methods for you. It’s done using Groovy script which is a supported template language of IntelliJ IDEA.

Demo

Let’s watch the demo first.

As you can see, if you create the type and data you get the constructor methods as well.

Get the Template Settings

Please download the settings jar file.

Download: IntelliJ IDEA Live template settings

If you’re worried about what are inside. Just unzip it and have a look. There are a few empty files and only one XML file called scala.xml containing the template info.

How to import

  • File -> Import Settings

  • Select the downloaded IntelliJ IDEA ADT template settings file.

  • Make sure Live templates (schemes) is ticked and press the OK button.

  • Restart the IDEA.

All done.

  • If you want to check whether it’s imported correctly or not, open the Preferences

  • Editor -> Live Templates -> Expand scala. If you can see adt and adtData, you’re ready to use it.

Now try! Just type adt in any .scala file in the IntelliJ IDEA.

adt to create ADT initially and adtData to add more data.

Comments