For reasons beyond my control, my method receives inputs in the form of a tuple. This tuple should only contain instances of Foo, i.e., it should look like (Foo, Foo ... Foo) and should not have String or Int inside. I want to check this at compile-time instead of throwing an exception at runtime. How can I achieve this?
Below is the code I currently have, which is not right:
def f(tupleOfFoos: Tuple): Tuple = {
for (x <- tupleOfFoos) assert(x.isInstanceOf[Foo])
mapTuple(tupleOfFoos, irrelevantFunction)
}
I am open to using Shapeless or the new features introduced in Dotty/Scala 3.
In Scala 2, with Shapeless, you can do this (Scastie):
LiftAllensures there's an instance ofFoo =:= Xfor everyXinH, andgenmakes sure thatTandHare not completely unrelated types.In Dotty, you can add an evidence parameter with a match type for this:
This will allow you to call
f((Foo(), Foo(), Foo()))but notf((1, 2, 3)).Homogenousis a recursive match type with a base case ofEmptyTuple. If a tuple is empty, then it's not filled with non-Foos, so the type becomesDummyImplicit, which has an implicit already in scope. Otherwise, we check if it looks like(H, ...)/H *: t, in which case we need to check if the rest of the tuple (t) is also valid. If it doesn't match that second case, we know the tuple is invalid, in which case the result isNothing, which sane people don't make implicit values of.If you want to use context bounds, you can make an additional curried type (Scastie):
Unfortunately, I haven't been able to get it to work with a single curried type (Scastie):