Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

scala

Why is a return statement required to allow this while statement to be evaluated properly? The following statement 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 produces the following error from scalac:

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

It appears that it's attempting to treat the block following the use as an inline statement rather than a lambda, but I'm not exactly sure why. Adding return after the while alleviates 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 runs as expected. Can anyone describe to me what is going on there exactly? This seems as though it should be a bug. It's been persistent across many versions of Scala though (tested 2.8.0, 2.9.0, 2.9.1)

like image 469
Scott S. McCoy Avatar asked Dec 06 '22 17:12

Scott S. McCoy


1 Answers

That's because it's use is declared as () => Unit, so the compiler expects the block you are giving use to return something that satisfies this signature.

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

like image 93
pedrofurla Avatar answered May 18 '23 13:05

pedrofurla