Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Scala - why an empty argument list is declared before implicit list

Tags:

scala

implicit

Some places (e.g. Play Form.bindFromRequest) use an empty parameter list before the implicit parameter list. Why? IMHO, it has the disadvantage of requiring extra parentheses when the parameter is explicitly passed as in form.bindFromRequest()(request). Not sure what is the advantage then?

like image 947
Jacob Eckel Avatar asked Nov 09 '22 18:11

Jacob Eckel


1 Answers

A def with a parameter list has a different type than one with no parameter list. This doesn't matter under direct invocation, but if you pass that method as an argument to another method, it does.

In example, if you define your method like so:

def func1 = { println("Hello"); 1 }

You can't pass it to this method:

def consume(f: () => Double) = // ...

as it's type is simply Double, albeit a very lazy one. On the other hand this function will work fine:

def func2() = { println("Hello"); 2 }

I'm not saying this is the explicit reason why they did it, but if they had an actual reason, it will almost certainly be tied to type.

EDIT:

The difference between them in practical terms it mostly comes down to where they can be used.

The call-by-value item can only be used in a parameter list to a function/method (afaik). Since it can only be passed in a parameter list, you can't store it in a variable and use it in multiple locations (without changing it to an explicit instance of T).

And as you can see here, they aren't interchangeable per se:

scala> def f(s: => String) { println(s) }
f: (s: => String)Unit

scala> def s1 = () => { "Hello" }
s1: () => String

scala> f(s1)
<console>:10: error: type mismatch;
 found   : () => String
 required: String
              f(s1)
                ^

So imagine I wanted to store an array of callbacks that users pass to me.. I can't use => T here:

scala> val a: Array[=> Int] = Array()
<console>:1: error: identifier expected but '=>' found.
       val a: Array[=> Int] = Array()
                    ^

scala> val a: Array[() => Int] = Array()
a: Array[() => Int] = Array()

So if I want to store such items, and pass them around internally, using => T (and keeping it lazily evaluated) is not an option.

I think it's best to not think of the => in => T and () => T as meaning the same thing. Hope this helps a little.

like image 114
Rich Henry Avatar answered Nov 14 '22 22:11

Rich Henry