Home > Enterprise >  How to type a tuple of any length but only having options in scala 3
How to type a tuple of any length but only having options in scala 3

Time:09-13

How could I have something like

var tuple : (Option[Any]) | (Option[Any], Option[Any]) | (Option[Any], Option[Any], Option[Any]) | (Option[Any], Option[Any], Option[Any], Option[Any])  

But more elegantly?

CodePudding user response:

Scala 3 unions are flashy and fun, but there's something to be said for slightly more traditional methods, especially when you end up with a type signature that requires a horizontal scrollbar.

In this case, since your priority seems to be type safety on the individual tuple elements, I might suggest a sealed trait with case classes for children.

sealed trait MySpecialTuple

case class MyOneTuple(
  val field: Option[Any],
) extends MySpecialTuple

case class MyTwoTuple(
  val leftHandSide: Option[Int],
  val rightHandSide: Option[String],
) extends MySpecialTuple

...

var tuple: MySpecialTuple

Since it's sealed, you can exhaustively pattern match against it to figure out what's inside. If you want to add additional functionality (like a way to get the "length" of the thing or some other property), that can be a method on MySpecialTuple. The point, here, is to offload the incredible complexity of "this thing can be one of ten different shapes" onto a bunch of named, well-documented classes rather than hiding it away in a one-liner variable declaration.

CodePudding user response:

You can do something like this in scala3.0:

scala> type OptTuple[T <: Tuple] = T match
     |   case Option[_] *: t => OptTuple[t]
     |   case EmptyTuple => DummyImplicit
     |

scala> case class MyTuple[T <: Tuple : OptTuple](tuple: T)
// defined case class MyTuple

scala> val t1 = MyTuple((Option(1), Option("a"), Option(3.0)))
val t1: MyTuple[(Option[Int], Option[String], Option[Double])] = MyTuple((Some(1),Some(a),Some(3.0)))

scala> val t2 = MyTuple((Option(1), Option("a"), 3.0))
-- Error: ----------------------------------------------------------------------
1 |val t2 = MyTuple((Option(1), Option("a"), 3.0))
  |                ^
  |     Match type reduction failed since selector  Double *: EmptyTuple.type
  |     matches none of the cases
  |
  |         case Option[_] *: t => OptTuple[t]
  |         case EmptyTuple => DummyImplicit
1 error found
  • Related