I can the require method in Scala's Predef class with a String as second argument, e.g.
require ("foo" == "bar", "foobar")
First a thought the require method is overloaded for different parameters as second argument. But it is not. The Signature of the require method (Scala 2.9.1) is:
require(requirement: Boolean, message: ⇒ Any): Unit
Why is the above method call possible ?
I don't fully understand the question, but here is a bit of explanation. require
has one overloaded version in Predef
:
def require(requirement: Boolean) //...
def require(requirement: Boolean, message: => Any) //...
The second one is a bit confusing due to message: => Any
type. It would probably be easier if it was simply:
def require(requirement: Boolean, message: Any) //...
The second parameter is of course a message that is suppose to be appended to error message if assertions is not met. You could imagine message
should be of String
type but with Any
you can simply write:
require(x == 4, x)
Which will add actual value of x
(of type Int
) into an error message if it is not equal to 4
. That's why Any
was chosen - to allow arbitrary value.
But what about : =>
part? This is called call by name and basically means: evaluate this parameter when it is accessed. Imagine the following snippet:
require(list.isEmpty, list.size)
In this case you want to be sure the list
is empty - and if it is not, add the actual list
size to the error message. However with normal call convention the list.size
part must be evaluated before the method is called - which might be wasteful. With call by name convention the list.size
is only evaluated the first time it is used - when the error message is constructor (if required).
The require
method existed in Predef
before scala had default parameters (introduced in 2.8), so overloading was the only option if you wanted default behaviour for a given parameter. As indicated by the message, the second argument may be anything, which is then used as the message
(by calling its toString
method) of the thrown IllegalArgumentException
, (if it is thrown - i.e. if the requirement fails).
Notice that the argument is, in fact, a call by name; that is, it is declared as => Any
, which means it will only be evaluated if the requirement fails.
This inflicts a performance penalty in the form of an object creation, but it may be useful in the case where the construction of your message is expensive (perhaps it requires some O(n) access to a data-structure).
The question is, why a String is valid type for the second argument while the signatures says it has to be a function
message: => Any
.
The signature doesn't say that. The signature says the second argument is of type Any
, and that this parameter is passed by name.
The "by name" is indicated by the prefixing =>
symbol which does not mean function -- a function is always indicated as input parameters => result type, with Function0
being () => type
.
Look up parameters "by value" and "by name".
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With