closing file pointer in Scala in Finally - scala

In the following code, I am reading no. of lines from a file. If something goes wrong, I'll like to close the file pointer. But how can I find out if f contains valid pointer or not?
def countLines(filename:String):Option[Int] = {
try{
val f = Source.fromFile(filename)
println(s"no. of lines ${f.getLines().size}")
Some(f.getLines.size)
} catch {
case ex: FileNotFoundException => {
println(s"file ${filename} not found")
None
}
} finally {
//f might not be a valid pointer depending on when the error occured
}
}
The book I am reading uses var to maintain state (if f is valid or not) but I am trying to avoid it for sake of using only immutable variables.
def countLines(filename:String):Option[Int] = {
var f:Option[Source] = None
try{
f = Some(Source.fromFile(filename))
println(s"no. of lines ${f.get.getLines().size}")
Some(f.get.getLines.size)
} catch {
case ex: FileNotFoundException => {
println(s"file ${filename} not found")
None
}
} finally {
for(i<-f){
println("closing file")
i.close()
}
}
}

A double Try(). This closes the io resource even if the getLines() fails, but only if the fromFile() succeeds.
import scala.util.Try
def countLines(filename: String): Option[Int] =
Try(io.Source.fromFile(filename)).fold(_ => None, {f =>
val count = Try(f.getLines().length)
f.close()
count.toOption
})

What do you think about this?
If you want Scala-way - i think it's good example for your task:
def countLines(filename: String): Try[Int] = Try(Source.fromFile(filename).getLines.toList.size)
def test() = {
val filename = "/etc/passwd"
countLines(filename) match {
case Success(n) => println(n)
case Failure(f) => println(f)
}
}
When n - is a number of our lines, and f - is a Throwable.

How about this:
def countLines(filename: String): Option[Int] = {
val file = Try(Source.fromFile(filename))
val count = file.map(_.getLines().size)
(for {
_ <- count.recoverWith { case _ => file.map(_.close()) }
lineCount <- count
} yield lineCount).toOption
}
Let's analyze it:
If file does not exist we will have failed Try instance and method returns None. In this case you do not need to clear any resources as no actual stream was created.
If getLines fails for any reason or anything else during processing goes south we will close created stream in first line of for comprehension
Hope it helps

Simply, how about this:
def numLines(fileName:String):Option[Int] = {
try {
val f = scala.io.Source.fromFile(fileName)
try { Some(f.getLines.size) }
catch { case ex: IOException =>
Console.err.println("i/o excetion")
None
}
finally { f.close() }
}
catch {
case ex: FileNotFoundException =>
Console.err.println("file not found")
None
}
}

Related

Primitive Try/match handling in scala

I wrote the following piece of code
def info(): MyCaseClass = {
Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} match {
case Failure(f) => {
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}
case Success(s) => s
}
}
Is there an even shorter way to deal with the fact that the file system operation could result in an exception so I handle it as above. Like can I not just somehow have to deal with failure case only. Like in case of Future exceptions, the future just does what it has to but for exceptions only we define recover and recoverWith. Something analogous is possible here?
Simply use try instead of Try:
def info(): MyCaseClass = {
try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} catch {
case f: Throwable => {
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}
}
}
Try has recover as well:
def info(): MyCaseClass = {
(Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
} recover {
case f =>
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
}).get
}
.getOrElse seems to be what you are looking for:
def info(): MyCaseClass = {
Try {
val fileSys = new File("somePath")
MyCaseClass(fileSys.getTotalSpace, fileSys.getUsableSpace)
}.getOrElse({
logger.error(s"Could not read information:${f.getStackTrace}")
MyCaseClass(0, 0)
})
}

Making a while-loop more scala-esqe

It is quite clear what the loop below accomplishes. I somewhat think that it could be made more scala-esque, but I can't quite see it. I'm posting this to see if anyone has more inspiration than me.
var bunnies: List[Bunny] = List.fill(nBunniesAtStart)(generateInitialBunny)
var doContinue = true
while (doContinue) {
val prevBunnies = bunnies
bunnies = evolveOneYear(bunnies)
print(bunnies, prevBunnies)
if (bunnies.isEmpty) {
println("\n\n\n No more bunnies...")
doContinue = false
} else {
println("Hit Enter to continue, or q + Enter to quit.\n")
doContinue = readLine.isEmpty()
}
}
I wrote this code as an answer to a codereview post.
EDIT:
thanks to #wingedsubmariner and #Kigyo, I have this alternative:
val startBunnies: List[Bunny] = List.fill(nBunniesAtStart)(generateInitialBunny)
userInputLoop(startBunnies, "")
#tailrec
def userInputLoop(bunnies: List[Bunny], userInput: String): Unit = {
if (userInput.nonEmpty) println("Exiting")
else evolveOneYear(bunnies) match {
case Nil =>
print(Nil, bunnies)
println("No more bunnies...")
case newBunnies =>
print(newBunnies, bunnies)
userInputLoop(newBunnies, readLine())
}
}
Or
val startBunnies: List[Bunny] = List.fill(nBunniesAtStart)(generateInitialBunny)
userInputLoop(startBunnies)
#tailrec
def userInputLoop(prevBunnies: List[Bunny]): Unit = {
evolveOneYear(prevBunnies) match {
case Nil =>
print(Nil, prevBunnies)
println("No more bunnies...")
case bunnies =>
print(bunnies, prevBunnies)
if (readLine().nonEmpty) println("Exiting.")
else userInputLoop(bunnies)
}
}
EDIT 2:
Another attempt, build from some ideas of Chris Martin and Ben Kovitz:
class NoMoreBunniesException extends Exception("No more bunnies...")
class UserStoppageException extends Exception("Exiting at your request.")
def doesUserWantToContinue(): Try[_] = {
println("Hit Enter to continue, or q + Enter to quit.\n");
if (readLine().isEmpty) Success() else Failure(new UserStoppageException)
}
def validateBunnies(bunnies: List[Bunny]): Try[_] = {
if (bunnies.isEmpty) Failure(new NoMoreBunniesException)
else Success()
}
def checkNotEmptyAndUserContinuation(bunnies: List[Bunny]): Try[_] =
validateBunnies(bunnies).flatMap(_ => doesUserWantToContinue)
val firstBunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
println(s"${buildBunniesReport(firstBunnies).toString}\n\n")
val timeline = Stream.iterate(firstBunnies)(evolveOneYear)
val timelineWithPrev = timeline.tail.zip(timeline)
val statusAndReportTimeline = timelineWithPrev.map {
case (bunnies, prevBunnies) =>
(checkNotEmptyAndUserContinuation(bunnies), buildFullReport(bunnies, prevBunnies))
}
// main loop including user interaction
statusAndReportTimeline.takeWhile {
case (Success(_), _) => true
case (Failure(e), report) => { println(s"${report}\n\n${e.getMessage}"); false }
}.foreach { case (_, report) => println(report) }
Here's a solution that's more functional (perhaps also more abstruse):
val firstBunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
val timeline = Stream.iterate(firstBunnies)(evolveOneYear)
val inputLines = Source.fromInputStream(System.in).getLines()
timeline.zip(timeline.tail).iterator
.takeWhile({ case (previousBunnies, bunnies) => previousBunnies.nonEmpty })
.zip(Iterator.single("") ++ inputLines)
.takeWhile({ case (_, input) => input.isEmpty })
.map({ case ((previousBunnies, bunnies), _) =>
(bunnies, previousBunnies) + (
if (bunnies.isEmpty) "No more bunnies..."
else "Hit Enter to continue, or q + Enter to quit."
)
})
.foreach(println)
You can make it more idiomatic scala by using a tail-recursive function instead of a while loop and eliminiating the vars:
import scala.annotation.tailrec
val startBunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
#tailrec
def loop(prevBunnies: List[Bunny]): Unit = {
val bunnies = evolveOneYear(prevBunnies)
print(bunnies, prevBunnies)
if (bunnies.isEmpty) {
println("\n\n\n No more bunnies...")
} else {
println("Hit Enter to continue, or q + Enter to quit.\n")
if (readLine.isEmpty)
loop(bunnies)
}
}
loop(startBunnies)
// Separate the functional logic ...
val firstBunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
val timeline = Stream.iterate(firstBunnies)(evolveOneYear)
for ((previousBunnies, bunnies) <- timeline zip timeline.tail) {
// ... from the I/O.
print(bunnies, previousBunnies)
if (bunnies.isEmpty) {
println("No more bunnies...")
return
} else {
println("Hit Enter to continue, or q + Enter to quit.")
}
if (readLine().nonEmpty) return
}
Here's yet another way to do it, aiming for clarity and simplicity.
import util.control.Breaks._
val bunniesStream: Stream[List[String]] = firstBunnies #:: bunniesStream.map(evolveOneYear)
breakable {
for (bunnies <- bunniesStream) {
println(bunnies)
if (bunnies.isEmpty) {
println("No more bunnies...");
break
} else {
println("Hit Enter to continue, or q + Enter to quit.\n");
if (!readLine().isEmpty) break
}
}
}
The use of breakable suggests that this is not idiomatic Scala code.
The more I consider this, the more I'm bothered by the idea of blocking on the InputStream over a human timescale. So here's an approach using Akka!
The setup:
import akka.actor.{Actor, ActorRef, ActorSystem, Props}
// The actor system
val system = ActorSystem()
// The actors: a bunny farm, and a console to interact with it
val farm = system.actorOf(Props[BunnyFarm])
system.actorOf(Props(classOf[BunnyConsole], farm))
// Keep alive until the actor system terminates
system.awaitTermination()
The bunny farm:
object BunnyFarm {
// Define the messages that a bunny farm uses
case object Advance
case class Result(bunnies: Seq[Bunny], previousBunnies: Seq[Bunny])
}
class BunnyFarm extends Actor {
import BunnyFarm._
// A bunny farm's state consists of a list of its bunnies
var bunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
def receive = {
case Advance =>
// Advance the state of the farm one year
val previousBunnies = bunnies
bunnies = evolveOneYear(bunnies)
// Reply to the sender with the result
sender ! Result(bunnies = bunnies, previousBunnies = previousBunnies)
}
}
The console interface:
class BunnyConsole(farm: ActorRef) extends Actor with akka.camel.Consumer {
// Read from stdin
def endpointUri = "stream:in"
// Initially advance the farm once
farm ! BunnyFarm.Advance
def receive = {
case m: akka.camel.CamelMessage => self forward m.bodyAs[String]
// Each string message represents a line of user input
case s: String => s match {
case "" => farm ! BunnyFarm.Advance
case _ => quit()
}
// When the bunny farm sends a result...
case r: BunnyFarm.Result =>
println(s"Previous bunnies: ${r.previousBunnies}")
println(s"New bunnies: ${r.bunnies}")
if (r.bunnies.nonEmpty) {
println("Hit Enter to continue, or q + Enter to quit.")
} else {
println("No more bunnies...")
quit()
}
}
// Terminate the actor system, thus halting the program
def quit() = context.system.shutdown()
}
Dependencies:
com.typesafe.akka:akka-actor
com.typesafe.akka:akka-camel
org.apache.camel:camel-stream
Edit - The same solution refactored for brevity.
Setup:
import akka.actor.{Actor, ActorSystem, Props}
val system = ActorSystem()
system.actorOf(Props(classOf[BunnyConsole]))
system.awaitTermination()
Console:
class BunnyConsole extends Actor with akka.camel.Consumer {
def endpointUri = "stream:in"
var bunnies = List.fill(nBunniesAtStart)(generateInitialBunny)
advance()
def receive = {
case m: akka.camel.CamelMessage => m.bodyAs[String] match {
case "" => advance()
case _ => quit()
}
}
def advance() {
val previousBunnies = bunnies
bunnies = evolveOneYear(bunnies)
print(bunnies, previousBunnies)
if (bunnies.nonEmpty) {
println("Hit Enter to continue, or q + Enter to quit.")
} else {
println("No more bunnies...")
quit()
}
}
def quit() = context.system.shutdown()
}
Here's yet another approach. It's horrible. I post it here in the hope that it will inspire someone to re-do its essential idea in a more readable or at least conventional way.
val bunniesStream = Stream.iterate(firstBunnies)(evolveOneYear)
case class Interaction(bunnies: List[String]) {
lazy val print: Unit = println(bunnies)
lazy val continue: Boolean = {
print
if (bunnies.isEmpty) { println("No more bunnies..."); false }
else userOK
}
lazy val userOK: Boolean = {
println("Hit Enter to continue, or q + Enter to quit.\n");
readLine().isEmpty
}
}
bunniesStream.map(Interaction).takeWhile(_.continue).force
The idea that I'm trying to implement here is to get the user's input by lazy evaluation. What makes it hard to do the loop in a functional style is the fact that you don't know when to stop the loop until after you've read the user's input, but you might need to stop the loop before reading the user's input.
The last line bundles all the input and output into an expression. Without .force, that expression should evaluate to an object which you can then pass to other functions as you like. This seems to follow the spirit of functional programming. No input or output should happen until you do a .force. Except it does, because there's something fundamentally wrong with my approach. I don't quite know what it is. Maybe the error has something to do with my mixing decision-making with input/output in the Interaction class.

StackOverflowError while using Scala Iterator

I am trying to save a large data set (50MB) into file. But I get the following error:
java.lang.StackOverflowError
at scala.collection.Iterator$$anon$12.hasNext(Iterator.scala:350)
at scala.collection.Iterator$$anon$12.hasNext(Iterator.scala:350)
...
It looks to me like a recursion problem but I can't find where it would come from. Plase help. Function that makes the Iterator[String]:
override def toJsonIterator: Iterator[String] = {
val lastId = listMap.keys.toList.sorted.last
def evalJS(id: Int): String = {
Json.prettyPrint(listMap(id).toJsonValue) + (if(id != lastId) "," else "")
}
listMap.keys.toList.sorted
.foldLeft(Iterator("{"))( (sum, id) => sum ++ Iterator(evalJS(id)) ) ++ Iterator("}")
}
The save to file code:
private def write(st: Iterator[String], file: String): Unit = {
if (st.isEmpty) return ()
val f = new File(file)
if (!f.getParentFile().exists()) f.getParentFile().mkdirs()
if (!f.exists()) f.createNewFile()
val p = new java.io.PrintWriter(f)
try {
while(st.hasNext) {
p.println(st.next())
}
}
catch {
case e:Exception => println("Error: could not write to file \""+file+"\" because: "+e)
}
finally { p.close() }
}

How to generalize a method?

I'm trying to generalize the following code:
def fetchUrl = {
try {
val lineList = Source.fromURL(url).getLines.toList
process(lineList)
}
catch {
case ex: java.net.UnknownHostException => ex.printStackTrace()
}
}
I want to be able to fetch URL's (fromURL) and files (fromFile) with the same method. Is it possible to generalize this code to archive this?
I figured I could use pattern matching for this but I don't know how.
def fetchSource(src: Source, str: String) = src match {
case ??? => Source.fromURL(url).getLines.toList
case ??? => Source.fromFile(str).getLines.toList
}
Is there a way to get this right?
Thanks in advance.
You could check if a string is a Url (for this example I'm using java.net.URL, but you can do it with UrlValidator as well)
Something like this:
def isUrl(url: String) = try {
new java.net.URL(url)
true
} catch {
case _ => false
}
import scala.io.Source
def fetchSource(src:String) = if(isUrl(src)) {
Source.fromURL(src).getLines.toList
} else {
Source.fromFile(src).getLines.toList
}
The simplest solution is to have one method that will fetch a given Source, and two wrapper methods that build Source from File or URL.
def fetchSource(source: io.Source) =
try {
val lineList = source.getLines.toList
process(lineList)
} catch {
case ex: java.net.UnknownHostException => ex.printStackTrace()
}
def fetchFile(file: java.io.File) = fetchSource(io.Source.fromFile(file))
def fetchUrl(url: java.net.URL) = fetchSource(io.Source.fromURL(url))

What Automatic Resource Management alternatives exist for Scala?

I have seen many examples of ARM (automatic resource management) on the web for Scala. It seems to be a rite-of-passage to write one, though most look pretty much like one another. I did see a pretty cool example using continuations, though.
At any rate, a lot of that code has flaws of one type or another, so I figured it would be a good idea to have a reference here on Stack Overflow, where we can vote up the most correct and appropriate versions.
Chris Hansen's blog entry 'ARM Blocks in Scala: Revisited' from 3/26/09 talks about about slide 21 of Martin Odersky's FOSDEM presentation. This next block is taken straight from slide 21 (with permission):
def using[T <: { def close() }]
(resource: T)
(block: T => Unit)
{
try {
block(resource)
} finally {
if (resource != null) resource.close()
}
}
--end quote--
Then we can call like this:
using(new BufferedReader(new FileReader("file"))) { r =>
var count = 0
while (r.readLine != null) count += 1
println(count)
}
What are the drawbacks of this approach? That pattern would seem to address 95% of where I would need automatic resource management...
Edit: added code snippet
Edit2: extending the design pattern - taking inspiration from python with statement and addressing:
statements to run before the block
re-throwing exception depending on the managed resource
handling two resources with one single using statement
resource-specific handling by providing an implicit conversion and a Managed class
This is with Scala 2.8.
trait Managed[T] {
def onEnter(): T
def onExit(t:Throwable = null): Unit
def attempt(block: => Unit): Unit = {
try { block } finally {}
}
}
def using[T <: Any](managed: Managed[T])(block: T => Unit) {
val resource = managed.onEnter()
var exception = false
try { block(resource) } catch {
case t:Throwable => exception = true; managed.onExit(t)
} finally {
if (!exception) managed.onExit()
}
}
def using[T <: Any, U <: Any]
(managed1: Managed[T], managed2: Managed[U])
(block: T => U => Unit) {
using[T](managed1) { r =>
using[U](managed2) { s => block(r)(s) }
}
}
class ManagedOS(out:OutputStream) extends Managed[OutputStream] {
def onEnter(): OutputStream = out
def onExit(t:Throwable = null): Unit = {
attempt(out.close())
if (t != null) throw t
}
}
class ManagedIS(in:InputStream) extends Managed[InputStream] {
def onEnter(): InputStream = in
def onExit(t:Throwable = null): Unit = {
attempt(in.close())
if (t != null) throw t
}
}
implicit def os2managed(out:OutputStream): Managed[OutputStream] = {
return new ManagedOS(out)
}
implicit def is2managed(in:InputStream): Managed[InputStream] = {
return new ManagedIS(in)
}
def main(args:Array[String]): Unit = {
using(new FileInputStream("foo.txt"), new FileOutputStream("bar.txt")) {
in => out =>
Iterator continually { in.read() } takeWhile( _ != -1) foreach {
out.write(_)
}
}
}
Daniel,
I've just recently deployed the scala-arm library for automatic resource management. You can find the documentation here: https://github.com/jsuereth/scala-arm/wiki
This library supports three styles of usage (currently):
1) Imperative/for-expression:
import resource._
for(input <- managed(new FileInputStream("test.txt")) {
// Code that uses the input as a FileInputStream
}
2) Monadic-style
import resource._
import java.io._
val lines = for { input <- managed(new FileInputStream("test.txt"))
val bufferedReader = new BufferedReader(new InputStreamReader(input))
line <- makeBufferedReaderLineIterator(bufferedReader)
} yield line.trim()
lines foreach println
3) Delimited Continuations-style
Here's an "echo" tcp server:
import java.io._
import util.continuations._
import resource._
def each_line_from(r : BufferedReader) : String #suspendable =
shift { k =>
var line = r.readLine
while(line != null) {
k(line)
line = r.readLine
}
}
reset {
val server = managed(new ServerSocket(8007)) !
while(true) {
// This reset is not needed, however the below denotes a "flow" of execution that can be deferred.
// One can envision an asynchronous execuction model that would support the exact same semantics as below.
reset {
val connection = managed(server.accept) !
val output = managed(connection.getOutputStream) !
val input = managed(connection.getInputStream) !
val writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(output)))
val reader = new BufferedReader(new InputStreamReader(input))
writer.println(each_line_from(reader))
writer.flush()
}
}
}
The code makes uses of a Resource type-trait, so it's able to adapt to most resource types. It has a fallback to use structural typing against classes with either a close or dispose method. Please check out the documentation and let me know if you think of any handy features to add.
Here's James Iry solution using continuations:
// standard using block definition
def using[X <: {def close()}, A](resource : X)(f : X => A) = {
try {
f(resource)
} finally {
resource.close()
}
}
// A DC version of 'using'
def resource[X <: {def close()}, B](res : X) = shift(using[X, B](res))
// some sugar for reset
def withResources[A, C](x : => A #cps[A, C]) = reset{x}
Here are the solutions with and without continuations for comparison:
def copyFileCPS = using(new BufferedReader(new FileReader("test.txt"))) {
reader => {
using(new BufferedWriter(new FileWriter("test_copy.txt"))) {
writer => {
var line = reader.readLine
var count = 0
while (line != null) {
count += 1
writer.write(line)
writer.newLine
line = reader.readLine
}
count
}
}
}
}
def copyFileDC = withResources {
val reader = resource[BufferedReader,Int](new BufferedReader(new FileReader("test.txt")))
val writer = resource[BufferedWriter,Int](new BufferedWriter(new FileWriter("test_copy.txt")))
var line = reader.readLine
var count = 0
while(line != null) {
count += 1
writer write line
writer.newLine
line = reader.readLine
}
count
}
And here's Tiark Rompf's suggestion of improvement:
trait ContextType[B]
def forceContextType[B]: ContextType[B] = null
// A DC version of 'using'
def resource[X <: {def close()}, B: ContextType](res : X): X #cps[B,B] = shift(using[X, B](res))
// some sugar for reset
def withResources[A](x : => A #cps[A, A]) = reset{x}
// and now use our new lib
def copyFileDC = withResources {
implicit val _ = forceContextType[Int]
val reader = resource(new BufferedReader(new FileReader("test.txt")))
val writer = resource(new BufferedWriter(new FileWriter("test_copy.txt")))
var line = reader.readLine
var count = 0
while(line != null) {
count += 1
writer write line
writer.newLine
line = reader.readLine
}
count
}
For now Scala 2.13 has finally supported: try with resources by using Using :), Example:
val lines: Try[Seq[String]] =
Using(new BufferedReader(new FileReader("file.txt"))) { reader =>
Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
}
or using Using.resource avoid Try
val lines: Seq[String] =
Using.resource(new BufferedReader(new FileReader("file.txt"))) { reader =>
Iterator.unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
}
You can find more examples from Using doc.
A utility for performing automatic resource management. It can be used to perform an operation using resources, after which it releases the resources in reverse order of their creation.
I see a gradual 4 step evolution for doing ARM in Scala:
No ARM: Dirt
Only closures: Better, but multiple nested blocks
Continuation Monad: Use For to flatten the nesting, but unnatural separation in 2 blocks
Direct style continuations: Nirava, aha! This is also the most type-safe alternative: a resource outside withResource block will be type error.
There is light-weight (10 lines of code) ARM included with better-files. See: https://github.com/pathikrit/better-files#lightweight-arm
import better.files._
for {
in <- inputStream.autoClosed
out <- outputStream.autoClosed
} in.pipeTo(out)
// The input and output streams are auto-closed once out of scope
Here is how it is implemented if you don't want the whole library:
type Closeable = {
def close(): Unit
}
type ManagedResource[A <: Closeable] = Traversable[A]
implicit class CloseableOps[A <: Closeable](resource: A) {
def autoClosed: ManagedResource[A] = new Traversable[A] {
override def foreach[U](f: A => U) = try {
f(resource)
} finally {
resource.close()
}
}
}
How about using Type classes
trait GenericDisposable[-T] {
def dispose(v:T):Unit
}
...
def using[T,U](r:T)(block:T => U)(implicit disp:GenericDisposable[T]):U = try {
block(r)
} finally {
Option(r).foreach { r => disp.dispose(r) }
}
Another alternative is Choppy's Lazy TryClose monad. It's pretty good with database connections:
val ds = new JdbcDataSource()
val output = for {
conn <- TryClose(ds.getConnection())
ps <- TryClose(conn.prepareStatement("select * from MyTable"))
rs <- TryClose.wrap(ps.executeQuery())
} yield wrap(extractResult(rs))
// Note that Nothing will actually be done until 'resolve' is called
output.resolve match {
case Success(result) => // Do something
case Failure(e) => // Handle Stuff
}
And with streams:
val output = for {
outputStream <- TryClose(new ByteArrayOutputStream())
gzipOutputStream <- TryClose(new GZIPOutputStream(outputStream))
_ <- TryClose.wrap(gzipOutputStream.write(content))
} yield wrap({gzipOutputStream.flush(); outputStream.toByteArray})
output.resolve.unwrap match {
case Success(bytes) => // process result
case Failure(e) => // handle exception
}
More info here: https://github.com/choppythelumberjack/tryclose
Here is #chengpohi's answer, modified so it works with Scala 2.8+, instead of just Scala 2.13 (yes, it works with Scala 2.13 also):
def unfold[A, S](start: S)(op: S => Option[(A, S)]): List[A] =
Iterator
.iterate(op(start))(_.flatMap{ case (_, s) => op(s) })
.map(_.map(_._1))
.takeWhile(_.isDefined)
.flatten
.toList
def using[A <: AutoCloseable, B](resource: A)
(block: A => B): B =
try block(resource) finally resource.close()
val lines: Seq[String] =
using(new BufferedReader(new FileReader("file.txt"))) { reader =>
unfold(())(_ => Option(reader.readLine()).map(_ -> ())).toList
}
While Using is OK, I prefer the monadic style of resource composition. Twitter Util's Managed is pretty nice, except for its dependencies and its not-very-polished API.
To that end, I've published https://github.com/dvgica/managerial for Scala 2.12, 2.13, and 3.0.0. Largely based on the Twitter Util Managed code, no dependencies, with some API improvements inspired by cats-effect Resource.
The simple example:
import ca.dvgi.managerial._
val fileContents = Managed.from(scala.io.Source.fromFile("file.txt")).use(_.mkString)
But the real strength of the library is composing resources via for comprehensions.
Let me know what you think!