Scala, generic tuple

  • A+

I have a generic method that can accept any tuple of any size, the only constraint is that the first element of this tuple should be of type MyClass.

Something like this:

trait MyTrait[T <: (MyClass, _*)] {   getMyClass(x: T): MyClass = x._1 } 

I've tried this

trait MyTrait[T <: (MyClass, _) with (MyClass, _, _) with (MyClass, _, _) with ...] {   getMyClass(x: T): MyClass = x._1 } 

but I get the error unboud wildcard type


If you want to do this without either boilerplate or runtime reflection, Shapeless is your best bet. You can use the IsComposite type class to put type-level constraints on the first element of a tuple:

import shapeless.ops.tuple.IsComposite  trait MustBeFirst  class MyClass[P <: Product](p: P)(implicit ev: IsComposite[P] { type H = MustBeFirst }) 

And then:

scala> new MyClass(good2) res0: MyClass[(MustBeFirst, String)] = MyClass@5297aa76  scala> new MyClass(good3) res1: MyClass[(MustBeFirst, String, Int)] = MyClass@3f501844  scala> new MyClass(good4) res2: MyClass[(MustBeFirst, String, Symbol, Int)] = MyClass@24e15478  scala> new MyClass(bad2) <console>:15: error: could not find implicit value for parameter ev: shapeless.ops.tuple.IsComposite[(String, Int)]{type H = MustBeFirst}        new MyClass(bad2)        ^ 

If you need to use a trait, you can put the ev (for "evidence") requirement inside the definition instead of in the constructor:

trait MyTrait[P <: Product] {   implicit def ev: IsComposite[P] { type H = MustBeFirst } } 

Now any class instantiating MyTrait will have to provide evidence that P is a tuple with MustBeFirst as its first element.


:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: