Too much curry!
What does a compiled curried method in Scala look like in java? Compile this:
object Concat {
def concat(s: String)(ss: String) = s + ss
def concat(s: String)(i: Int) = i + s
}
Now inspect the resulting class with javap:
Compiled from "Concat.scala"
public final class Concat extends java.lang.Object{
public static final java.lang.String concat(java.lang.String, java.lang.String);
}
After compilation curried methods look like normal, multi-parameter methods. It doesn’t matter how many parameter lists you define, nor how many parameters each list takes; in the end you get a plain old method. Knowing this we should expect overloading to work fine, so let’s overload our curried method:
object Concat {
def concat(s: String)(ss: String) = s + ss
def concat(s: String)(i: Int) = i + s
}
As expected, this compiles, and javap gives expected output:
public final class Concat extends java.lang.Object{
public static final java.lang.String concat(java.lang.String, int);
public static final java.lang.String concat(java.lang.String, java.lang.String);
}
Great, let’s use it!
object Concat {
def concat(s: String)(ss: String) = s + ss
def concat(s: String)(i: Int) = i + s
}
object Concatter {
def greet(who: String, msg: String) = Concat.concat(who)(msg)
}
And compile:
Concat.scala:7: error: ambiguous reference to overloaded definition,
both method concat in object Concat of type (s: String)(i: Int)String
and method concat in object Concat of type (s: String)(ss: String)java.lang.String
match argument types (String)
def greet(who: String, msg: String) = Concat.concat(who)(msg)
^
one error found
Well, that was unexpected! The compiler let us overload a curried method, but it won’t let us use either of them. The error tells us that the compiler is unable to disambiguate the method. This seems strange as we’re explicitly passing values for all arguments. Try as we may, there simply is no way to use these methods as defined. As it turns out, this is a problem of scope. Let’s try different access modifiers:
object Concat {
def concat(s: String)(ss: String) = s + ss
protected def concat(s: String)(i: Int) = i + s
}
object Concatter {
def greet(who: String, msg: String) = Concat.concat(who)(msg)
}
This compiles because Concat.concat(s: String)(i: Int) is not in scope at the call site (it’s not accessible). However, within Concat both are in scope:
object Concat {
def concat(s: String)(ss: String) = s + ss
protected def concat(s: String)(i: Int) = i + s
def con = concat("")("")
}
Concat.scala:4: error: ambiguous reference to overloaded definition,
both method concat in object Concat of type (s: String)(i: Int)String
and method concat in object Concat of type (s: String)(ss: String)java.lang.String
match argument types (java.lang.String)
def con = concat("")("")
^
one error found
If you’re overloading curried methods, remember that you must demarcate their potential scopes with access modifiers. Two overloaded curried methods with the same access levels will never be callable; they will compile unless you try to use them. Perhaps a more fundamental lesson to learn from this is to eschew method overloading in general, always.
blog comments powered by Disqus
-
alexsaintx reblogged this from iamchrislewis and added:
the general spirit...functional programming, though for
-
iamchrislewis posted this