2
def createFloatBuffer(data: Option[Quaternion]*): Option[FloatBuffer] = data match {
  ...
}

def createFloatBuffer(data: Option[Vector3f]*): Option[FloatBuffer] = data match {
  ...
}

This code will not compile due to the two methods having the same method signature. None type would not know which method to call.

I could just rename the methods, however I would like to this overloading style in my code.

miniwolf
  • 339
  • 1
  • 4
  • 18

2 Answers2

8

After type erasure this two methods become createFloatBuffer(data: Option), and all types information is lost and not available at run time.

As a workaround I can suggest you to use TypeClass pattern.

case class Quaternion(v: Int)
case class Vector3f(v: Int)

case class FloatBuffer(v: Int)

sealed trait FloatBufferBuilder[T] {
  def createFloatBuffer(data: Option[T]): Option[FloatBuffer]
}

implicit object QuaternionFloatBufferBuilder extends FloatBufferBuilder[Quaternion] {
  def createFloatBuffer(data: Option[Quaternion]) = data.map(d => FloatBuffer(d.v))
}

implicit object Vector3fFloatBufferBuilder extends FloatBufferBuilder[Vector3f] {
  def createFloatBuffer(data: Option[Vector3f]) = data.map(d => FloatBuffer(d.v))
}

def createFloatBuffer[T : FloatBufferBuilder](data: Option[T]): Option[FloatBuffer] =
  implicitly[FloatBufferBuilder[T]].createFloatBuffer(data)


println(createFloatBuffer(Some(Quaternion(1))))
println(createFloatBuffer(Some(Vector3f(1))))

Magnet Pattern could also interesting for you: http://spray.io/blog/2012-12-13-the-magnet-pattern/

Eugene Zhulenev
  • 9,469
  • 2
  • 28
  • 38
  • 1
    This is a very interesting solution, I think the best solution would be to avoid giving Option type to methods and instead match them out before I call the method. – miniwolf Aug 03 '14 at 12:53
1

This is the use case for:

scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
<console>:10: error: double definition:
def f(is: Int*): Int at line 10 and
def f(ds: Double*): Int at line 10
have same type after erasure: (is: Seq)Int
       object X { def f(is: Int*) = 42 ; def f(ds: Double*) = 43 }
                                             ^

scala> object X { def f(is: Int*) = 42 ; def f(ds: Double*)(implicit dummy: DummyImplicit) = 43 }
defined object X

scala> X f 1
res2: Int = 42

scala> X f 1.0
res3: Int = 43
som-snytt
  • 38,672
  • 2
  • 41
  • 120
  • Can you add some explanation of how that gets around the issue? – The Archetypal Paul Aug 02 '14 at 19:16
  • @Paul Which issue? The second param list disambiguates the runtime sigs, and `X f (Seq.empty: _*)` picks the first (if that's desirable), same as issue with `f(None)` in OP. – som-snytt Aug 02 '14 at 20:14
  • I'm not getting how the second param list disambiguates the runtime sigs. Maybe I'm being dense. – The Archetypal Paul Aug 02 '14 at 21:53
  • @Paul I can't find a canonical SO answer, but http://stackoverflow.com/a/5736428/1296806. I hope it's clear that (Seq)Int differs from (Seq, Dummy)Int. – som-snytt Aug 03 '14 at 05:31
  • Yeah this feels more like a hack than anything else, say I want to overload the method with an additional type I would have to make a new dummy object. – miniwolf Aug 03 '14 at 12:51
  • Yep, I was being dense. For some reason, I'd read the implicit dummy as being part of the object, not a second arg to f(Double). As @miniwolf says, seems a bit of a hack even if it works... – The Archetypal Paul Aug 03 '14 at 13:06
  • @miniwolf They don't call it evil for nothing. http://stackoverflow.com/a/2512001/1296806 – som-snytt Aug 03 '14 at 20:56