Why is a return statement required to allow this when a statement needs to be properly evaluated?

Why is a return statement required for this while statement to evaluate properly? The following instruction allows

import java.io.File import java.io.FileInputStream import java.io.InputStream import java.io.BufferedReader import java.io.InputStreamReader trait Closeable { def close () } trait ManagedCloseable extends Closeable { def use (code: () => Unit) { try { code() } finally { this.close() } } } class CloseableInputStream (stream: InputStream) extends InputStream with ManagedCloseable { def read = stream.read } object autoclose extends App { implicit def inputStreamToClosable (stream: InputStream): CloseableInputStream = new CloseableInputStream(stream) override def main (args: Array[String]) { val test = new FileInputStream(new File("test.txt")) test use { val reader = new BufferedReader(new InputStreamReader(test)) var input: String = reader.readLine while (input != null) { println(input) input = reader.readLine } } } } 

This results in the following error from scalac:

 autoclose.scala:40: error: type mismatch; found : Unit required: () => Unit while (input != null) { ^ one error found 

It seems like it is trying to process the block following use as inline, not lambda, but I'm not quite sure why. Adding return after fixing the error:

 test use { val reader = new BufferedReader(new InputStreamReader(test)) var input: String = reader.readLine while (input != null) { println(input) input = reader.readLine } return } 

And the application works as expected. Can someone describe to me what exactly is going on there? This seems to be a mistake. It was persistent in many versions of Scala, though (tested 2.8.0, 2.9.0, 2.9.1)

+4
source share
4 answers

This is because use declared as () => Unit , so the compiler expects the block that you give use to return what satisfies this signature.

It seems that you want to turn the entire block into a by-name parameter to do this: change def use (code : () => Unit) to def use (code : => Unit) .

+8
source

() => Unit is the type of the Function0 object, and you need the use expression to be of a type that obviously isn't. => Unit is a parameter by name that you should use instead.

You may find my answer to this question useful.

+3
source

To understand the essence of the matter, blocks are not lambdas . A block in Scala is a volume limiter, nothing more.

If you wrote

 test use { () => val reader = new BufferedReader(new InputStreamReader(test)) var input: String = reader.readLine while (input != null) { println(input) input = reader.readLine } } 

Then you will have a function (indicated by () => ), which is separated by a block.

If use was declared as

 def use (code: => Unit) { 

Then the syntax you used will work, but not because of any lambda thing. This syntax indicates that the parameter is passed by name, which, roughly speaking, means that you would accept the entire expression passed as the parameter (i.e., the entire block) and replace it with code inside the use body. The type code will be Unit , not a function, but the parameter will not be passed by value.

+3
source

return or return expr is of type Nothing . You can replace this for any type, since it never gives a value to the surrounding expression, instead it returns control to the caller.

In your program, it is masked as the required type () => Unit .

Here is sometimes a convenient use for this (although you can be tarnished as uniomatic, if you use it too often, do not tell anyone who heard it from me!)

 def foo(a: Option[Int]): Int = { val aa: Int = a.getOrElse(return 0) aa * 2 } 

For the record, you should probably write:

 def foo(a: Option[Int]): Int = a.map(_ * 2).getOrElse(0) 

You can get a sense of the compiler's mind by checking the output of scala -Xprint:typer -e <one-liner> . Add -Ytyper-debug if you like to sift through -Ytyper-debug channels!

 scala210 -Ytyper-debug -Xprint:typer -e 'def foo: Any = {val x: () => Any = { return }}' ... elided ... typed return (): Nothing adapted return (): Nothing to () => Any, 
+1
source

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


All Articles