3

Given an A, which may have optional fields, a and b:

case class A(a: Option[Int], b: Option[String])

I could define A as an Algebraic Data Type.

However, it would require 4 sub-classes to account for each None/Option choice:

sealed trait AADT
case class Aa(a: Int) extends AADT
case class Aab(a: Int, b: String) extends AADT
case class Ab(b: String) extends AADT
case object Neither extends AADT

I'd argue that this ADT is preferable to the above A option, which has Option types.

However, this type could quickly get out of hand with 3, 4, etc. fields.

Is there a third way to implement A, i.e. not using either my first or second implementation?

Community
  • 1
  • 1
Kevin Meredith
  • 38,251
  • 58
  • 190
  • 340
  • You realized that Option[A] is itself an ADT right? – pedrofurla Aug 24 '16 at 19:11
  • My first thought against your proposal would be to argue that Option itself already gives a few useful methods like map, flatMap, filter etc. But on other hand A is a monomorphic. – pedrofurla Aug 24 '16 at 19:14
  • 1
    One tried way (that is actually pretty boring) is to use `(Option[Int], Option[String])`. But to compensate this boredom I offer a forth option, use a Shapeless coproduct of Int, String, (Int, String) and Neither. – pedrofurla Aug 24 '16 at 19:17
  • Have you considered a factory `object` that would return an appropriate class depending on the provided parameters? – sebszyller Aug 24 '16 at 19:25
  • 1
    @pedrofurla I don't see how using a `Tuple` is any different than a case class in this instance. Please let me know what advantage you see. – Kevin Meredith Aug 24 '16 at 19:43
  • Tuple2 already exists. But yeah, it's essentially the same thing. But so will any other solution. – pedrofurla Aug 24 '16 at 19:55
  • 1
    @KevinMeredith You might be interested in this https://www.youtube.com/watch?v=YScIPA8RbVE, if you are not already familiar with the topic. It requires some Haskell knowledge, which I'd be glad to help if you need (very basic though). – pedrofurla Aug 24 '16 at 19:59

2 Answers2

4

Algebraically there is a third option that covers all combination

sealed trait A
case class Ao(o: Option[(Int, String)]) extends A //all or none
case class Ae(e: Either[Int, String]) extends A //first or second

I would definitely choose some sort of ADT if there is a separate domain name for each case.

Optional fields are good for data transferred objects (DTO)

Nazarii Bardiuk
  • 3,979
  • 1
  • 17
  • 22
0

This is the first thing that came to my mind and posting it in the comment section would be hardly readable. It definitely isn't a prettiest solution but might be 'good enough' for OP's case.

sealed trait AADT
case class Aa(a: Int) extends AADT
case class Aab(a: Int, b: String) extends AADT
case class Ab(b: String) extends AADT
case object Neither extends AADT

object AADTBuilder {
  def apply() = Neither
  def apply(a: Int) = Aa(a)
  def apply(a: Int, b: String) = Aab(a, b)
  def apply(b: String) = Ab(b)
}

And just call AADTBuilder with the right parameters.

sebszyller
  • 853
  • 4
  • 10