Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't a class val parameter be call-by-name?

Tags:

scala

I'm trying to use a class to aggregate as a single interface a bunch of proxies for API functions. A couple of these are nullary functions, but I don't want the act of including them in the class constructor to trigger the API calls. My solution right now is to wrap the call in a literal nullary function new myClass(() => apiCall) and then calling the member function explicitly. This isn't all that bad, but I'm wondering if there's a technical reason I can't just use a call-by-name parameter to pass lazy reference to the method?

Example:

scala> class MyClass(val apiCall: => String)
<console>:1: error: `val' parameters may not be call-by-name
       class MyClass(val apiCall: => String)

Edit I should have specified that my question is why a class can't have a val parameter. Added an example.

like image 338
acjay Avatar asked Jul 09 '14 20:07

acjay


People also ask

What is the difference between call-by-value and call by name?

This is because call-by-value functions compute the passed-in expression's value before calling the function, thus the same value is accessed every time. However, call-by-name functions recompute the passed-in expression's value every time it is accessed.

What is the difference between a call-by-value and call by name parameter in Scala?

In Scala when arguments pass through call-by-value function it compute the passed-in expression's or arguments value once before calling the function . But a call-by-Name function in Scala calls the expression and recompute the passed-in expression's value every time it get accessed inside the function.

Is Scala call by name?

For this circumstance, Scala offers call-by-name parameters. A call-by-name mechanism passes a code block to the call and each time the call accesses the parameter, the code block is executed and the value is calculated.

What do you understand by call by name?

Call by name is a a parameter passing scheme where the parameter is evaluated when it is used, not when the function is called.


1 Answers

A class can very well have call-by-name parameters, as long as they are not val or var:

> scala
Welcome to Scala version 2.11.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.7.0_55).
Type in expressions to have them evaluated.
Type :help for more information.

scala> class Foo(f: => Unit) {
     |   def run(): Unit = f
     | }
defined class Foo

scala> new Foo(println("hello"))
res0: Foo = Foo@5da6b8c6

scala> res0.run()
hello

The reason a val or var parameter cannot be by-name is simply that a class field cannot be by-name, no more than local variable, for that matter. So the following is invalid:

scala> class FooInvalid(val v: => Unit) {
<console>:1: error: `val' parameters may not be call-by-name
       class FooInvalid(val v: => Unit) {
                               ^

However, it is possible to have a by-name parameter that is assigned, as a function to a val field, like this (but then you have to use () as call site):

scala> class FooVal(v0: => Unit) {
     |   val v: () => Unit = () => v0
     | }
defined class FooVal

scala> new FooVal(println("hello"))
res2: FooVal = FooVal@75c145bc

scala> res2.v
res3: () => Unit = <function0>

scala> res2.v()
hello

Finally, instead of defining v as a val of type () => Unit, you can define it as def of type Unit. And then you get the behavior you probably wanted in the first place:

scala> class FooDef(v0: => Unit) {
     |   def v: Unit = v0
     | }
defined class FooDef

scala> new FooDef(println("hello"))
res5: FooDef = FooDef@2e04a041

scala> res5.v
hello

One could argue that the compiler should do this transformation itself, but that would not be consistent with the semantics that a val must be stable (e.g., with a stable value you can import x._ its members, which you cannot do with an unstable value) since a def (even without ()) is a not a stable value. Best to leave this small rewriting to the user rather than introduce a very weird unsoundness.

like image 50
sjrd Avatar answered Oct 20 '22 14:10

sjrd