22

Is there a more idiomatic way of opening a resource in Scala and applying methods to it than this method (translated directly from java):

var is: FileInputStream = null
try {
  is = new FileInputStream(in)
  func(is)
} catch {
  case e: IOException =>
    println("Error: could not open file.")
    println("       -> " + e)
    exit(1)
} finally {
  if(is) is.close()
}
Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
Aaron Yodaiken
  • 19,163
  • 32
  • 103
  • 184
  • 2
    You could try the "Automatic-Resource-Management" Library: https://github.com/jsuereth/scala-arm/wiki/basic-usage (I haven't used it) – Fabian Mar 01 '11 at 09:13
  • 1
    You are looking for something known as Automatic Resource Management, which is one of thew few features we can expect of Java 7. – Daniel C. Sobral Mar 01 '11 at 16:28

4 Answers4

19

The loan pattern is implemented in various ways in Josh Suereth's scala-arm library on github.

You can then use a resource like this:

val result = managed(new FileInputStream(in)).map(func(_)).opt 

which would return the result of func wrapped in an Option and take care of closing the input stream.

To deal with the possible exceptions when creating the resource, you can combine with the scala.util.control.Exception object:

import resource._
import util.control.Exception.allCatch

allCatch either { 
  managed(new FileInputStream(in)).map(func(_)).opt 
} match {
  case Left(exception) => println(exception)
  case Right(Some(result)) => println(result)
  case _ =>
}
huynhjl
  • 41,520
  • 14
  • 105
  • 158
13

Use the Loan pattern (dead link) non permanent link to new location.

shellholic
  • 5,974
  • 1
  • 20
  • 30
  • 1
    Is there any standard implementation of this in the Scala standard library, or should I just make my own in a util module? – Aaron Yodaiken Mar 01 '11 at 03:00
  • @aharon See the comment below your answer -- Josh Suereth's ARM library does this. – Daniel C. Sobral Mar 01 '11 at 16:27
  • @WinMyoHtet: it is now there https://wiki.scala-lang.org/display/SYGN/Loan but for now, there is note stating that they don't encourage creating permanent links – shellholic Mar 01 '12 at 13:42
5

That might be one case where it is not desirable to go functional. The allready mentioned loan pattern is only an encapsulation of the imparative version of error handling, but that has nothing to do with functional programming, and also doenst take care of error handling.

If you really wanted it functional you could do it with an error handling monad. For good reasons the link I provide is Haskell specific documentation to this, as Scala is not supporting this kind of "hardcore" functional practice so well.

I would reccomend to you to go the imperative way and use try catch finally... you could also extend the loan pattern with error handling but that means you have to either write special functions if you want to treat errors differently in some situations or you would have to pass over an partial function for error handling (which is nothing else than what you allready got inside the catch block in your code).

Martin Ring
  • 5,404
  • 24
  • 47
  • Do we need a monad for this? In Haskell you have the `bracket` function, http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Exception-Base.html#v:bracket, which is implemented in Scalaz as well. – Damian Nadales Sep 29 '16 at 09:01
0

Starting Scala 2.13, the standard library provides a dedicated resource management utility: Using.

It can be used in this case with FileInputStream as it implements AutoCloseable in order to play with an input file and, no matter what, close the file resource afterwards:

import scala.util.{Using, Failure}
import java.io.FileInputStream

Using(new FileInputStream(in)) {
  is => func(is)
}.recoverWith {
  case e: java.io.IOException =>
    println("Error: could not open file.")
    Failure(e)
}

Since Using produces a Try providing either the result of the operation or an error, we can work with the exception via Try#recoverWith.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190