Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does Scala's require method in Predef allow a String as argument?

Tags:

scala

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 ?

like image 929
John Threepwood Avatar asked May 20 '12 11:05

John Threepwood


3 Answers

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).

like image 74
Tomasz Nurkiewicz Avatar answered Nov 15 '22 09:11

Tomasz Nurkiewicz


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).

like image 20
oxbow_lakes Avatar answered Nov 15 '22 09:11

oxbow_lakes


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

like image 44
Daniel C. Sobral Avatar answered Nov 15 '22 10:11

Daniel C. Sobral