简体   繁体   中英

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?

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)

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"?

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
   ()
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM