What is the difference between def foo = {} and def foo() = {} in Scala?

北慕城南 提交于 2019-12-27 11:45:43

问题


Given the following constructs for defining a function in Scala, can you explain what the difference is, and what the implications will be?

def foo = {}

vs.

def foo() = {}

Update

Thanks for the quick responses. These are great. The only question that remains for me is:

If I omit the parenthesis, is there still a way to pass the function around? This is what I get in the repl:

scala> def foo = {}
foo: Unit

scala> def baz() = {}
baz: ()Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo)
<console>:10: error: type mismatch;
 found   : Unit
 required: () => Unit
              test(foo)
                   ^

scala> test(baz)
res1: () => Unit = <function0>

Update 2012-09-14

Here are some similar questions I noticed:

  1. Difference between function with parentheses and without
  2. Scala methods with no arguments

回答1:


If you include the parentheses in the definition you can optionally omit them when you call the method. If you omit them in the definition you can't use them when you call the method.

scala> def foo() {}
foo: ()Unit

scala> def bar {}
bar: Unit

scala> foo

scala> bar()
<console>:12: error: Unit does not take parameters
       bar()
          ^

Additionally, you can do something similar with your higher order functions:

scala> def baz(f: () => Unit) {}
baz: (f: () => Unit)Unit

scala> def bat(f: => Unit) {}
bat: (f: => Unit)Unit

scala> baz(foo)    

scala> baz(bar)
<console>:13: error: type mismatch;
 found   : Unit
 required: () => Unit
       baz(bar)
           ^
scala> bat(foo)

scala> bat(bar)  // both ok

Here baz will only take foo() and not bar. What use this is, I don't know. But it does show that the types are distinct.




回答2:


Let me copy my answer I posted on a duplicated question:

A Scala method of 0-arity can be defined with or without parentheses (). This is used to signal the user that the method has some kind of side-effect (like printing out to std out or destroying data), as opposed to the one without, which can later be implemented as val.

See Programming in Scala:

Such parameterless methods are quite common in Scala. By contrast, methods defined with empty parentheses, such as def height(): Int, are called empty-paren methods. The recommended convention is to use a parameterless method whenever there are no parameters and the method accesses mutable state only by reading fields of the containing object (in particular, it does not change mutable state).

This convention supports the uniform access principle [...]

To summarize, it is encouraged style in Scala to define methods that take no parameters and have no side effects as parameterless methods, i.e., leaving off the empty parentheses. On the other hand, you should never define a method that has side-effects without parentheses, because then invocations of that method would look like a field selection.




回答3:


To answer your second question, just add an _:

scala> def foo = println("foo!")
foo: Unit

scala> def test(arg: () => Unit) = { arg }
test: (arg: () => Unit)() => Unit

scala> test(foo _)
res10: () => Unit = <function0>

scala> test(foo _)()
foo!

scala>            



回答4:


I would recommend always start definition with a function like:

def bar {}

and only in cases, when you are forced, to change it to:

def bar() {}

Reason: Let's consider these 2 functions from a point of possible usage. How they can be infoked AND where they can be passed.

I would not call this a function at all:

def bar {}

It can be invoked as:

bar

but not as a function:

bar()

We can use this bar when we define a higher-order function with a call-by-name parameter:

def bat(f: => Unit) {
    f //you must not use (), it will fail f()
}

We should remember, that => Unit - is not even a function. You absolutely cannot work with a thunk as if it's a function insofar as you cannot choose to treat it as Function value to be stored or passed around. You can only trigger evaluations of the actual argument expression (any number of them). Scala: passing function as block of code between curly braces

A function, defined with () has a bigger scope for usage. It can be used exactly, in the same context, as bar:

def foo() = {}
//invokation:
foo
//or as a function:
foo()

It can be passed into a function with a call-by-name parameter:

bat(foo)

Additionally, if we define a higher-order function, that accepts not a call-by-name pamameter, but a real function:

def baz(f: () => Unit) {}

We can also pass foo to the baz:

baz(foo)

As we can see standard functions like foo have a bigger scope for usage. But using a functions defined without () plus defining higher-order functions, that accept call-by-name parameter, let us use more clear syntax.

If you do not try to archive a better, more readable code, or if you need ability to pass your piece of code both to function defined with a call-by-name parameter and to a function defined with a real function, then define your function as standard one:

def foo() {}

If you prefer to write more clear and readable code, AND your function has no side-effects, define a function as:

def bar {}

PLUS try to define your higher-order function to accept a call-by-name parameter, but not a function. Only when you are forced, only in this case use the previous option.



来源:https://stackoverflow.com/questions/7409502/what-is-the-difference-between-def-foo-and-def-foo-in-scala

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!