scalaslickslick-3.0hlist

How to read an element from a Scala HList?


There is very few readable documentation about HLists, and the answers I can find on SO come from outer space for a humble Scala beginner.

I encountered HLists because Slick can auto-generate some to represent database rows. They are slick.collection.heterogeneous.HList (not shapeless'). Example:

type MyRow = HCons[Int,HCons[String,HCons[Option[String],HCons[Int,HCons[String,HCons[Int,HCons[Int,HCons[Option[Int],HCons[Option[Float],HCons[Option[Float],HCons[Option[String],HCons[Option[String],HCons[Boolean,HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[String],HCons[Option[Int],HCons[Option[Float],HCons[Option[Float],HCons[Option[Float],HCons[Option[String],HCons[Option[String],HNil]]]]]]]]]]]]]]]]]]]]]]]]
def MyRow(a, b, c, ...): MyRow = a :: b :: c :: ... :: HNil

Now given one of these rows, I'd need to read one element, typed if possible. I just can't do that. I tried

row(4)  // error
row._4  // error
row.toList  // elements are inferred as Any
row match { case a :: b :: c :: x :: rest => x }  // "Pattern type is incompatible. Expected MyRow."
row match { case MyRow(_,_,_,_,_,x,...) => x }  // is not a case class like other rows
row match { HCons[Int,HCons[String,HCons[Option[String],HCons[Int,HCons[String, x]]]]] => x.head }  // error
row.tail.tail.tail.tail.head  // well, is that really the way??

Could somebody please explain how I can extract a specific value from that dinosaur?


Solution

  • I'd expect your row(0) lookup to work based on the HList API doc for apply. Here's an example I tried with Slick 3.1.1:

    scala> import slick.collection.heterogeneous._
    import slick.collection.heterogeneous._
    
    scala> import slick.collection.heterogeneous.syntax._
    import slick.collection.heterogeneous.syntax._
    
    scala> type MyRow = Int :: String :: HNil
    defined type alias MyRow
    
    scala> val row: MyRow = 1 :: "a" :: HNil
    row: MyRow = 1 :: a :: HNil
    
    scala> row(0) + 99
    res1: Int = 100
    
    scala> val a: String = row(1)
    a: String = a