m0meni
m0meni

Reputation: 16435

Scala overload function to add currying?

Started learning Scala today, and I was curious if you can overload a function to add currying like:

def add(x: Int, y: Int): Int = x + y
def add(x: Int)(y: Int): Int = x + y

But not only does this code not compile, but I've heard that overloading in Scala is not a good idea.

Is there a way to overload add such that it's curried without doing partial application, meaning both add(1, 2) and add(1)(2) work?

Upvotes: 2

Views: 355

Answers (3)

justAbit
justAbit

Reputation: 4256

For overloading it's necessary that function should either:

  • have different number of arguments
  • or have different argument type(s)

In your example both definitions of add are equivalent hence it's not overloading and you get compilation error.

You could use Kolmar's way (implicit object) below to call both add(1, 2) and add(1)(2) OR you can use Scala's Default Parameter to achieve same thing:

def add(a: Int, b: Int, c: Any = DummyImplicit) = a + b // c is default parameter
def add(a: Int)(b: Int) = a + b

About:

I've heard that overloading in Scala is not a good idea.

You can see Why "avoid method overloading"?

Upvotes: 2

Kolmar
Kolmar

Reputation: 14224

The problem is that those add functions are indistinguishable after JVM type erasure: during execution they are both (Int, Int)Int. But they are different during compilation, and Scala compiler can tell which one you are calling.

This means you have to make their argument lists different. To achieve that you can add an implicit argument list with a DummyImplicit argument:

def add(x: Int, y: Int)(implicit dummy: DummyImplicit): Int = x + y
def add(x: Int)(y: Int): Int = x + y

This DummyImplicit is provided by Scala library, and there is always an implicit value for it. Now the first function after erasure has a type (Int, Int, DummyImplicit)Int, and the second one (Int, Int)Int, so JVM can distinguish them.

Now you can call both:

add(1, 2)
add(1)(2)

Upvotes: 3

Ren
Ren

Reputation: 3455

I've got a way you can use add(1,2) and add(1)(2) but I wouldn't recommend it. It uses Scala's implicit definitions to have a different type for both methods, but use an implicit method to convert to the appropriate type.

case class IntWrapper(value: Int) // Purely to have a different type

object CurryingThing
{
  def add(x: IntWrapper)(y: IntWrapper) = x.value + y.value
  def add(x: Int, y: Int) = x + y

  // The magic happens here. In the event that you have an int, but the function requires an intWrapper (our first function definition), Scala will invoke this implicit method to convert it
  implicit def toWrapper(x: Int) = IntWrapper(x)

  def main(args: Array[String]) = {
   // Now you can use both add(1,2) and add(1)(2) and the appropriate function is called
   println(add(1,2)) //Compiles, prints 3
   println(add(1)(2)) // Compiles, prints 3
   ()
  }
}

Upvotes: 2

Related Questions