5

Let's assume the following:

class Wrapper1 {
  case class Condition(test: String)
}
object Wrapper1 extends Wrapper1

class Wrapper2 {
  case class Condition[A](test: String)
}
object Wrapper2 extends Wrapper2


class Test 
  type T = // whatever

  def test(fn: T => Wrapper1.Condition): X
  def test[R](fn: T => Wrapper2.Condition[R]): X
}

The problem is that because of type erasure those methods have the exact same type after erasure. It's easy to change the signature of the second with say:

def test[R](fn: T => Wrapper2.Condition[R])(implicit ev: R =:= R): X

But that confuses the compiler and using the test method in other places is impossible. For a number of design reasons I'm trying to keep the name of this method consistent. Is there any way to successfully do this?

Seth Tisue
  • 29,985
  • 11
  • 82
  • 149
flavian
  • 28,161
  • 11
  • 65
  • 105

2 Answers2

0

Seems this is NOT a duplicate of Scala double definition (2 methods have the same type erasure)

My suggestion... Just have a single method

def test[Cond: TypeTag](fn: T => Cond): X = {
  if(typeOf[T] <:< typeOf[Wrapper1.Condition]) ...
  else if(typeOf[T] <:< typeOf[Wrapper2.Condition[_]) ...
  else ...
}
Community
  • 1
  • 1
Kevin Wright
  • 49,540
  • 9
  • 105
  • 155
0

Finally able to work it out. What I was after was a way to conditionally append to an HList. Basically multiple overloads of the same method had to co-exist because they would return a different kind of HList.

To only have one method, arguments needed to dictate what the final signature of the method looked like.

So let's assume the following, the test method had to return

def test[RR](arg: Type1[RR]): Wrapper[RR :: ExistingHList]

Or respectively:

def test(arg: Type2): Wrapper[ExistingList]

The same method would have to append to an Hlist depending on whether or not the argument satisfied certain conditions. The fix was as trivial as using shapeless.ops.hlist.Prepend, which will by default returning the existing HList in the event we try to append HNil to an hlist.

Making the argument of Type2 return an HNil or implicitly convert to something that would end up being HNil was the approach that worked.

Specifically:

  class Wrapper[PS <: HList] {
    def test[
      RR,
      HL <: HList,
      Out <: HList
    ](
      condition: T => Wrapper[HL]
    )(implicit prepend: Prepend.Aux[HL, PS, Out]): Wrapper[Out[
  }

This approach works if the condition function will return a Wrapper[HNil] for situations where the function doesn't need to modify the end return type. Functions who do modify are simply free to build up their own HList independently.

flavian
  • 28,161
  • 11
  • 65
  • 105