I have defined two partial functions (hashes), which I expect to take an optional second Boolean parameter:
def SHA1 = hash(MessageDigest.getInstance("SHA-1"))_
def MD5 = hash(MessageDigest.getInstance("MD5"))_
private def hash(algorithm:HashAlgorithm)(s:String, urlencode:Boolean = false) = {
val form = if (urlencode) "%%%02X" else "%02X"
(algorithm.digest(s.getBytes) map(form format _)).mkString
}
When I call the function with both parameters, it compiles, but with just one parameter I get a compilation error:
// First 3 tests are fine
val test1 = hash(MessageDigest.getInstance("SHA-1"))("foo", true)
val test2 = hash(MessageDigest.getInstance("SHA-1"))("foo")
val test3 = SHA1("foo", true)
// not enough arguments for method apply: (v1: String, v2: Boolean)String in trait Function2. Unspecified value parameter v2.
val test4 = SHA1("foo")
I just refactored this to use partial functions, and before I refactored I could force the hash function to use the default without any problem.
Any ideas why the partial function implementation fails to permit default arguments? Am I doing something wrong using both partial functions and currying together?
When you use partial application to generate a function, you lose the ability to call the default. A method is a static thing, so the compiler knows where to look up the default value; a function can be passed around into different contexts, so the compiler will not in general have the information it needs to be able to apply the default parameter.
To think about it another way, functions only know how many arguments they have. There's just one method, apply
, that you pass parameters into; otherwise you'd need some way (different types, presumably) to distinguish, for example, Function2-that-must-take-two-parameters and Function2-that-can-be-called-with-one-parameter-also-because-there-is-a-stored-default.