Just trying to complete an exercise for flattening nested Lists which can contain Ints, nested Lists, or null.
This is easy to do with List[Any]
but I was wondering if it's possible to get compile-time checking on the inputs/test values.
So test case
flatten(List(0, 2, List(List(2, 3), 8, List(List(100)), null, List(List(null))), -2))
should be(List(0, 2, 2, 3, 8, 100, -2))
But I'd want a test with (say) a String in it to fail compilation.
flatten(List(0, 2, List(List(2, 3), 8, List(List(100)), "null", List(List(null))), -2))
// should not compile
So I wrote this
object FlattenArray:
type NestedList[T] = Int | List[NestedList[_]] | Null
def flatten(xs: NestedList[_]): List[Int] =
xs match
case (x: Int) :: tail => x :: flatten(tail)
case (ys: List[_]) :: tail => flatten(ys) ::: flatten(tail)
case null :: tail => flatten(tail)
case Nil => Nil
case _ => throw new IllegalArgumentException("This should never happen")
Which does work in the first and fail compilation as expected in the second test case, but rather than a graceful error message, I get a stack overflow:
[error] java.lang.StackOverflowError
[error] dotty.tools.dotc.core.Types$Type.dealias1(Types.scala:1369)
[error] dotty.tools.dotc.core.Types$Type.dealias(Types.scala:1387)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:744)
[error] dotty.tools.dotc.core.Types$TypeMap.op$proxy16$1(Types.scala:5246)
[error] dotty.tools.dotc.core.Types$TypeMap.mapArgs(Types.scala:5246)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5281)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5345)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
[error] dotty.tools.dotc.core.Types$TypeMap.mapOver(Types.scala:5345)
[error] dotty.tools.dotc.typer.ImplicitRunInfo$$anon$1.apply(Implicits.scala:750)
<repeat last 8 lines ad infinitum>
So my questions are:
- Am I doing this right?? (Unsure in particular about the type parameter in the type declaration.) Is there a better way to achieve the compile time type check?
- Is this Scala 3's expected failure mode?