2

I am trying to "unwrap" a type variable from a generic type (without using reflection). E.g. in the case of an Option, the goal would be that the following (or similar) code compiles:

implicitly[OptionUnwrapper[Option[Int]] =:= Int]

I managed to come up with the following unwrapper:

trait OptionUnwrapper[T] {
  type Unwrap[_ <: Option[T]] = T
}

which can be used to as follows:

implicitly[OptionUnwrapper[Int]#Unwrap[Option[Int]] =:= Int]

The problem with this solutions is, that I have to declare the type (in my case Int) of interest, before it can be returned. Is there a way to leaf out this parameter like for instance in generic functions like:

def foo[T](x: Option[T]) = x.isDefined
foo[Int](Some(1)) // function call with unnecessary type parameter,
foo(Some(1))      // since compiler infers Int automatically

UPDATE 1 - Use Case:

In my actual use case, I want to receive a "tuple type" from a case class. i.e. lets say I have a case class

case class Person(name: (String, String), age: Int, hobbies: List[String])

I want something that yields the type of the unapplied Person. i.e.

type T = Tupled[Person] // T =:= Tuple3[Tuple2[String, String], Int, List[String]]

I tried to get to this point by using the type of the Person.unapply function, which would be

Function1[Person, Option[Tuple3[...]]]

From this point, the plan would be to "unwrap" the Function1[_, Option[X]] to X

Zwackelmann
  • 557
  • 1
  • 5
  • 19
  • 1
    Interesting question, but in this specific case, can't you just reverse the test? That is instead of testing something like `implicitly[OptionUnwrapper[T]#Res =:= Int]`, just test `implicitly[T =:= Option[Int]]`? I can imagine that it was only illustrative, if so can you elaborate on your specific use case? This may give room to alternate solutions to your actual need. – Régis Jean-Gilles Jul 02 '15 at 15:05
  • This should not compile, since ``T`` is not defined in this context, right? – Zwackelmann Jul 02 '15 at 19:18
  • I recommend that you take a look at the Shapeless library and see if anything there fits your case. My feeling is that if you cannot do it using shapeless, then it is probably very hard or impossible to do. :) – Johnny Everson Jul 02 '15 at 20:18
  • @Zwackelmann: T in this context represents whatever concrete `Option` type that you are testing against (in your specific example, it would be `Option[Int]`) – Régis Jean-Gilles Jul 03 '15 at 08:57
  • Regarding your update (use case), the first thing that strikes me is that the only way to write code that will give you the type of the companion's `unapply` method, for a given case class, is to write a macro (unless you're willing to to copy/paste the same code for every case class. And from the moment that you are commited to write a macro, you can as well write it to return the `Tuple` type directly (which won't be much harder). So no need for `OptionUnwrapper`. – Régis Jean-Gilles Jul 03 '15 at 08:57
  • @Régis Jean-Gilles Writing a small piece of boilerplate code for each case class would also be kind of okay. Until now I didn't do anything with macros but to have the cleanest solution this will probably be the best way. – Zwackelmann Jul 03 '15 at 11:58
  • @Jhonny Everson At first glance, I didn't see a feature in shapeless, that fits to my use case, but until now I only gave it 10 minutes - so I can't really tell right now. I think I will have a look at macro programming first - sounds more promising to me :) – Zwackelmann Jul 03 '15 at 12:02
  • If you are willing to use a macro, I have already provided a macro that fits the bill: http://stackoverflow.com/questions/30728759/how-to-do-generic-tuple-case-class-conversion-in-scala/30731802#30731802. With it you could just do `val PersonFactory = CaseClassFactory[Person]; type PersonTuple = PersonFactory.Tuple` – Régis Jean-Gilles Jul 03 '15 at 12:15

1 Answers1

1

(Note that I'm addressing the actual use case instead of the original "Unwrap type variables" question)

As I said in a comment, If you are willing to use a macro, I have already provided a macro that fits the bill:

How to do generic tuple -> case class conversion in Scala?

You can then just do:

val PersonFactory = CaseClassFactory[Person]
type PersonTuple = PersonFactory.Tuple

But given that you are also ready to put up with some boilerplate for each case class, you can also go for a macro-less solution:

implicit class TupleTypeProvider[O,T](unapply: O => Option[T]) { type Tuple = T }
def tupleTypeProvider[O,T](implicit p: TupleTypeProvider[O,T]) = p
// Usage
case class Person(name: (String, String), age: Int, hobbies: List[String])
val personTupleInfo = tupleTypeProvider(Person.unapply _)
type PersonTuple = personTupleInfo.Tuple
// Let's check:
implicitly[PersonTuple =:= Tuple3[Tuple2[String, String], Int, List[String]]]

Or similarly:

implicit class TupleTypeProvider[O,T](tupled: T => O) { type Tuple = T }
def tupleTypeProvider[O,T](implicit p: TupleTypeProvider[O,T]) = p
// Usage
case class Person(name: (String, String), age: Int, hobbies: List[String])
val personTupleInfo = tupleTypeProvider((Person.apply _).tupled)
type PersonTuple = personTupleInfo.Tuple
// Let's check:
implicitly[PersonTuple =:= Tuple3[Tuple2[String, String], Int, List[String]]]
Community
  • 1
  • 1
Régis Jean-Gilles
  • 32,541
  • 5
  • 83
  • 97