Why does Scala require a method in Predef to accept a String argument?

I can use the require method in the Scala Predef class with String as the second argument, for example.

require ("foo" == "bar", "foobar") 

First, the idea that the require method is overloaded for different parameters as a second argument. But this is not so. Signature of the require method (Scala 2.9.1):

 require(requirement: Boolean, message: β‡’ Any): Unit 

Why is it possible to call the above method?

+6
source share
4 answers

I do not quite understand the question, but here is a little 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 the type message: => Any . It would be easier if it were simple:

 def require(requirement: Boolean, message: Any) //... 

The second parameter is, of course, the message that should be added to the error message if the statements are not executed. You can imagine that message should be of type String , but with Any you can simply write:

 require(x == 4, x) 

Which will add the actual x value (of type Int ) to the error message if it is not 4 . That's why Any was chosen - to allow an arbitrary value.

But what about : => parts? This is called a 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 that list empty - and if it is not, add the actual size of list to the error message. However, with a normal call agreement, the list.size part must be evaluated before the method is called - which can be wasteful. When called by name, the list.size is evaluated only on first use β€” when the error message is a constructor (if required).

+21
source

The require method existed in Predef before scala had default parameters (introduced in 2.8), so overloading was the only option if you wanted the default behavior for this parameter. As indicated in the message, the second argument can be everything that is then used as message (by calling its toString method) thrown by IllegalArgumentException (if it is selected - that is, if the requirement is not met).

Note that the argument is essentially a call by name ; that is, it is declared as => Any , which means that it will be evaluated only in case of failure .

This imposes a performance penalty in the form of creating an object, but it can be useful when building your message is expensive (it may require some O (n) access to the data structure).

+3
source

The question is why String is a valid type for the second argument, while signatures say it should be a message: => Any function.

The signature does not say that. The signature says that the second argument is of type Any and this parameter is passed by name.

"by name" is indicated by the prefix symbol => , which does not mean a function - the function is always indicated as input parameters => the type of the result, while Function0 is () => type .

See the "by value" and "by name" options.

+2
source

The answer is pretty simple: you expect a second argument

 require(boolean: Boolean, message: => Any): Unit 

to be a function for anyone and ask why String works, even if it's not a function.

Divide this by: a fixed String is nothing more than a function that

  • does not accept any arguments
  • does not require that the bracket () called
  • gives the same result with every call

In fact, the following two statements are equivalent in Scala:

 def x: String = "ABC" // const value, even though 'def' implies a function val x: String = "ABC" 

So you can say that => Any is done using String .

-1
source

Source: https://habr.com/ru/post/916192/


All Articles