Klang: How To Solve Overloading?

I haven’t had much time to work on Klang since my vacation ended, but I’ve been thinking about how to solve overloading. Note that this post contains pseudo-code that bears resemblance to, but is not actual Klang code — these are just thoughts so far.

Given types Double and Vector2(x: Double, y: Double), there are mathematical operations that take both types as operands in different combinations, but have the same name. For example, multiplication:

a: Double * b: Double = // intrinsic operation a * b
a: Double * v: Vector2 = Vector2(a * v.x, a * v.y)
v: Vector2 * a: Double = Vector2(a * v.x, a * v.y)

Solution 1: Allow overloading of class methods

package klang
class Double {
  def *(that: Double) = // intrinsic this * that

package vecmath
extending Double {
  def *(v: Vector2) = Vector2(this * v.x, this * v.y)

Solution 1a: Allow overloading of package level functions

package klang
def *(a: Double, b: Double) = // intrinsic a * b

package klang.vecmath
def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)

Solution 2: Allow for Haskell-style type classes

package klang
typeclass Multiplication[A, B, C] {
  def *(a: A, b: B): C
instance Multiplication[Double, Double, Double] {
  def *(a: Double, b: Double) = // intrinsic a * b

package klang.vecmath
instance Multiplication[Double, Vector2, Vector2] {
  def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)

Pros and Cons

The first solution of allowing method/function overloading as in Java or Scala will certainly complicate things, especially when I introduce some form of inheritance (currently there is none). However, I’m not sure the second method, which is more like the Haskell way of handling overloading, is any better. Especially the third type class argument (return type) will be confusing: am I then allowed to also provide an

instance Multiplication[Double, Vector2, String]

which differs only in the last argument. Obviously it shouldn’t be so: if selecting a type class instance based on method return type was allowed, that wouldn’t work with Klang’s Scala style type inference. Maybe the type class could have an abstract type member instead:

typeclass Multiplication[A, B] {
  type Result
  def *(a: A, b: B): Result
instance Multiplication[Double, Vector2] {
  type Result = Vector2
  def *(a: Double, v: Vector2) = Vector2(a * v.x, a * v.y)

But I haven’t really decided whether to even have type classes or type members. There seems to be a lot more ceremony required with type classes compared to simply allowing overloading methods or module-level functions. And I’m not sure if that provides any real advantage…

I could say that defining a function *(a: Double, b: Vector2) creates an implicit type class *[A, B] and an implicit instance of it *[Double, Vector2]. It would be equivalent to the manually defined type classes, wouldn’t it? Except in the manual case you could put division into the same type class with multiplication, but that would still require more ceremony than simple overloading.

And what of functions like max(a: Double, b: Double) and max(a: Collection[Double])? It would be nice to be able to do have the 2-argument version for performance reasons. Type classes wouldn’t necessarily solve that unless one could abstract over method argument arity.

I should probably read more literature to make better informed decisions about these things, just haven’t gotten around to those parts yet :)

What do you think? Do you have an opinion about which way to go or any pointers to reading material?

2 thoughts on “Klang: How To Solve Overloading?

  1. I like the type class approach to overloading. There’s a related idea that I’m not sure has been implemented – “Modular Type Classes”. Essentially it’s a way of simulating type classes using an SML-like module system (plus an extension to allow “importing” of canonical structures/functors into scope). This is very much like Scala “poor man’s” type classes via implicits. The paper is beyond me at the moment but the talk slides make a lot of sense.


Leave a Reply

Please log in using one of these methods to post your comment:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s