0

I'd like to overload a method based on generics - so something like this:

case class Indexed2dArr[Dim0Type, Dim1Type] (
  indices: (List[Dim0Type], List[Dim1Type]),
  array: List[List[Float]],
) {
  def getSliceAtIndexLocation(i: Dim0Type): (List[Dim1Type], List[Float]) = ???
  def getSliceAtIndexLocation(i: Dim1Type): (List[Dim0Type], List[Float]) = ???
}

So if getSliceAtIndexLocation is called with a parameter of Dim0Type, it returns a single-dimensioned slice of the orginal array, with an index of Dim1Type. And vice-versa for calling with Dim1Type.

This raises a double definition compiler error - that the two methods have the same type after type erasure, this type being (i: Object): Tuple2. Is there a valid way to wrangle this or is it straight-up impossible?

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
Chris J Harris
  • 1,597
  • 2
  • 14
  • 26
  • 6
    You can use the `DummyImplicit` which basically exists for this. Or you can use **typelcasses**. – Luis Miguel Mejía Suárez Aug 29 '20 at 04:19
  • @LuisMiguelMejíaSuárez - thank you - If you'd like to put the DummyImplicit method as an answer then I'll accept it. Would you mind explaining how typeclasses would help here? – Chris J Harris Aug 29 '20 at 04:35
  • @LuisMiguelMejíaSuárez - sorry, I understand what you mean by the typeclass-based approach now. But would this not require me to specify a typeclass for every possible concrete type for Dim0Type and Dim1Type? – Chris J Harris Aug 29 '20 at 05:03
  • 1
    @Chrisper No, just for `Dim0Type` and `Dim1Type`. – Dmytro Mitin Aug 29 '20 at 08:58

1 Answers1

3

Try either DummyImplicit

case class Indexed2dArr[Dim0Type, Dim1Type] (
  indices: (List[Dim0Type], List[Dim1Type]),
  array: List[List[Float]],
) {
  def getSliceAtIndexLocation(i: Dim0Type): (List[Dim1Type], List[Float]) = ???
  def getSliceAtIndexLocation(i: Dim1Type)(implicit 
    di: DummyImplicit): (List[Dim0Type], List[Float]) = ???
}

or type class pattern

case class Indexed2dArr[Dim0Type, Dim1Type] (
  indices: (List[Dim0Type], List[Dim1Type]),
  array: List[List[Float]],
) {
  def getSliceAtIndexLocation[A](i: A)(implicit tc: TC[A]): tc.Out = tc(i)

  trait TC[A] {
    type B
    type Out = TC.MkOut[B]
    def apply(i: A): Out
  }
  object TC {
    type MkOut[B] = (List[B], List[Float])

    type Aux[A, B0] = TC[A] { type B = B0 }
    def instance[A, B0](f: A => MkOut[B0]): Aux[A, B0] = new TC[A] {
      override type B = B0
      override def apply(i: A): Out = f(i)
    }
  
    implicit val dim0Type: Aux[Dim0Type, Dim1Type] = instance(i => ???)
    implicit val dim1Type: Aux[Dim1Type, Dim0Type] = instance(i => ???)
  }
}

or magnet pattern

import scala.language.implicitConversions

case class Indexed2dArr[Dim0Type, Dim1Type] (
  indices: (List[Dim0Type], List[Dim1Type]),
  array: List[List[Float]],
) {
  def getSliceAtIndexLocation(m: Magnet): m.Out = m()

  trait Magnet {
    type B
    type Out = Magnet.MkOut[B]
    def apply(): Out
  }
  object Magnet {
    type MkOut[B] = (List[B], List[Float])

    type Aux[B0] = Magnet { type B = B0 }
    def instance[B0](x: MkOut[B0]): Aux[B0] = new Magnet {
      override type B = B0
      override def apply(): Out = x
    }

    implicit def dim0Type(i: Dim0Type): Aux[Dim1Type] = instance(???)
    implicit def dim1Type(i: Dim1Type): Aux[Dim0Type] = instance(???)
  }
}
Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
  • thank you - it is going to take a while before I fully get my head around this but it works. – Chris J Harris Aug 29 '20 at 23:35
  • just for my own interest here, but presumably this cannot be done with an unknown number of generic arguments, ie varadic generics? – Chris J Harris Aug 29 '20 at 23:40
  • @Chrisper In Scala there are no variadic generics, but there is [`HList`](https://github.com/milessabin/shapeless/wiki/Feature-overview:-shapeless-2.0.0#heterogenous-lists): `case class SomeClass[L <: HList]()` `SomeClass[A :: B :: C :: HNil]()`. Type class can be defined correspondingly. – Dmytro Mitin Aug 30 '20 at 00:05
  • thanks - I've just started using that library and it looks very interesting. For the time being I am struggling to get all this stuff working with non-variadic generic parameters so I think I'll keep it simple for the time being, but it's nice to know there are other options out there when the time comes. – Chris J Harris Aug 30 '20 at 00:09