Search code examples
scalascala-3

How to normalise a Union Type (T | Option[T])?


I have the following case class:

case class Example[T](
    obj: Option[T] | T = None,
)

This allows me to construct it like Example(myObject) instead of Example(Some(myObject)).

To work with obj I need to normalise it to Option[T]:

  lazy val maybeIn = obj match
    case o: Option[T] => o
    case o: T => Some(o)

the type test for Option[T] cannot be checked at runtime

I tried with TypeTest but I got also warnings - or the solutions I found look really complicated - see https://stackoverflow.com/a/69608091/2750966

Is there a better way to achieve this pattern in Scala 3?


Solution

  • I don't know about Scala3. But you could simply do this:

    case class Example[T](v: Option[T] = None)
    
    object Example {
     def apply[T](t: T): Example[T] = Example(Some(t))
    }
    
    

    One could also go for implicit conversion, regarding the specific use case of the OP:

    import scala.language.implicitConversions
    
    case class Optable[Out](value: Option[Out])
    
    object Optable {
      implicit def fromOpt[T](o: Option[T]): Optable[T] = Optable(o)
      implicit def fromValue[T](v: T): Optable[T] = Optable(Some(v))
    }
    
    case class SomeOpts(i: Option[Int], s: Option[String])
    
    object SomeOpts {
      def apply(i: Optable[Int], s: Optable[String]): SomeOpts = SomeOpts(i.value, s.value)
    }
    
    println(SomeOpts(15, Some("foo")))