Question

I have the following method:

def lift[P <: Product, L <: HList](params: P)(implicit hl: Generic.Aux[P, L]) = {
  directive[L](_(hl to params))
}

and it perfectly works if i pass more then two arguments:

val result  = lift("string", 'a', 10) // compiles
val result2 = list(true, 5) // compiles

But when i'm passing a single argument it can't resolve implicit:

val failes = lift("string") 

It can't find Generic implicit for [String, Nothing], why does it work in other cases?

Was it helpful?

Solution

You're seeing the result of auto-tupling, which is a Scala (mis-)feature that causes lift(true, 5) to be parsed as lift((true, 5)) when there's no lift method with the appropriate number of values (two, in this case). The compiler won't automatically wrap a single value in a Tuple1, however—you just get a compiler error.

See for example this answer for more details about auto-tupling, and this thread for some reasons auto-tupling is a terrible thing to include in your language.

There are a couple of possible workarounds. The first would be to create an implicit conversion from values to Tuple1, as suggested in this answer. I wouldn't personally recommend this approach—every implicit conversion you introduce into your code is another mine in the minefield.

Instead I'd suggest avoiding autotupling altogether. Write out list((true, 5)) explicitly—you get a lot of extra clarity at the cost of only a couple of extra characters. Unfortunately there's no comparable literal support for Tuple1, so you have to write out lift(Tuple1("string")), but even that's not too bad, and if you really wanted you could define a new liftOne method that would do it for you.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top