Omid
Omid

Reputation: 1989

runtime conversion of List to HList

I want to have a generic list of different types and I want to get objects with specific type.

I have this structure:

trait Parent
case class A() extends Parent
case class B() extends Parent
case class C() extends Parent

I may define different lists with different size of:

val list:List[Parent] = A() :: B() :: C() :: C() ::Nil //or any size or ordering

I want to cast this in runtime to Hlist of A,B,C,C. .toHlist[] need types of elements which should be infer in runtime. What would be Shapeless way of it? Is there any way to convert it to tuples?

Upvotes: 4

Views: 1905

Answers (2)

Florian Kirmaier
Florian Kirmaier

Reputation: 572

The following function can convert your list to a HList:

def listToHList(x: List[_]): HList = {
  if(x == Nil) HNil
  else x.head :: listToHList(x.tail)
}

For your sample, you can use it like the following:

listToHList(list).asInstanceOf[A :: B :: C :: HNil]

Upvotes: 0

Vladimir Matveev
Vladimir Matveev

Reputation: 127711

You can't do it. Note that

should be infer in runtime

is a contradiction. Type inference works in compile time only.

In other words, when you write something like

val list: A :: B :: C :: C :: HNil = ...

the type of list variable is known at compile time. It is impossible to assign a type to a variable at runtime, it just doesn't make sense. Suppose it would be possible, and you would have a magical method toHlistMagical:

val list: List[Parent] = A() :: B() :: C() :: C() :: Nil
val hlist = list.toHlistMagical  // infers to  A :: B :: C :: C :: HNil

Now let's change it a bit:

def getHlist(list: List[Parent]) = list.toHlistMagical

Now what return type do you expect for this function to have? Bear in mind that it can be called with various lists, not only those which contain A, B, C, C instances in this order:

getHlist(C() :: B() :: A() :: A() :: Nil)

It could be Any, but then you can just go with List anyway because there is no HList anymore, so you don't get any extra type safety.

That's the reason why toHlist needs types:

def getHlist(list: List[Parent]) = list.toHlist[A :: B :: C :: C :: HNil]

getHlist now has return type Option[A :: B :: C :: C :: HNil], because you specified the exact type you want, and toHlist will be able to perform runtime validation of the list structure and return Some if the list does actually contain these types in this order or None if it does not.

Upvotes: 2

Related Questions