Making a while-loop more scala-esqe - scala

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.

Related

Unable to use for comprehension to resolve Future

I have this Action which should return a Future[Result] but I am unable to code it using for comprehension. This is the first time I am using for comprehension so I am also not sure if this is how I should use for.
Also, would someone comment on whether the usage of for is correct?
def verifyUser(token:String) = Action.async{
implicit request => { //the function takes a token
val tokenFutureOption:Future[Option[UserToken]] = userTokenRepo.find(UserTokenKey(UUID.fromString(token))) //checkc if the token exists in the db (db returns a Future)
for(tokenOption<- tokenFutureOption) yield { //resolve the future
tokenOption match {
case Some(userToken) =>{//token exists
val userOptionFuture = userRepo.findUser(userToken.loginInfo)//find user to which the token belongs. Another db request which returns a Future
for(userOption <- userOptionFuture) yield {//resolve future
userOption match {
case Some(user) =>{//user exists
val newInternalProfile = user.profile.internalProfileDetails.get.copy(confirmed=true) //modify user's profile
val newProfile = UserProfile(Some(newInternalProfile),user.profile.externalProfileDetails)
val confirmedUser = user.copy(profile=newProfile)
val userOptionFuture :Future[Option[User]] = userRepo.updateUser(confirmedUser) //update profile with new value. Another db operation with returns a Future
for(userOption <- userOptionFuture) yield {//resolve future
userTokenRepo.remove(UserTokenKey(UUID.fromString(token)))//remove the token
// Ok("user verified") //I WANT TO RETURN SUCCESS RESPONSE HERE BUT CODE DOESN'T COMPILE IF I UNCOMMENT THIS
}
}
case None =>{ //user doesn't exist
// Ok("user verified") //I WANT TO RETURN FAILURE RESPONSE HERE BUT CODE DOESN'T COMPILE IF I UNCOMMENT THIS
}
}
}
}
case None =>{//INVALID TOKEN RECEIVED
Redirect("http://localhost:9000/home"+";signup=error")//TODOM - pick from config //I CAN RETURN Redirect (WHICH IS OF SAME TYPE AS OK I.E. RESULT) BUT WHY AM I NOT ABLE TO USE OK ABOVE
}
}
}//THIS IS THE END OF FIRST FOR LOOP. HOW DO I HANDLE FAILURES IN THE FUTURE?
}
}
You are using Future, Option which are Monads and the idea behind them being helpful to sequence the computations just like Functors but also with capability to specify what happens next. .flatMap is what Monads have allow that which can be used as for yield for readability.
So in your example you can compose the api using sequence of operations.
object Api {
final case class UserTokenKey(uuid: UUID)
final case class UserToken(loginInfo: String)
object userTokenRepo {
def find(u: UserTokenKey) = {
Future.successful(Some(UserToken(loginInfo = "foundLoginInfo")))
}
def remove(u: UserTokenKey) = {
Future.successful(Some(UserToken(loginInfo = "")))
}
}
final case class User(profile: String)
object userRepo {
def findUser(u: String) = {
Future.successful(Some(User("profile")))
}
def updateUser(u: User) = {
Future.successful(Some(User("updated profile")))
}
}
def verifyUser(token: String)(implicit executionContext: ExecutionContext) = {
val user: Future[Option[UserToken]] = for {
tokenMaybe: Option[UserToken] <- userTokenRepo.find(UserTokenKey(UUID.fromString(token)))
userMaybe: Option[User] <-
tokenMaybe match {
case Some(t) => userRepo.findUser(t.loginInfo)
case _ => Future.successful(Option.empty[User])
}
updatedUserMaybe: Option[User] <-
userMaybe match {
case Some(u) => userRepo.updateUser(u)
case _ => Future.successful(Option.empty[User])
}
removedUserMaybe: Option[UserToken] <- userTokenRepo.remove(UserTokenKey(UUID.fromString(token)))
} yield removedUserMaybe
user
}
def httpLayer(request: String) = {
import scala.concurrent.ExecutionContext.Implicits.global
import play.api.mvc.Results
verifyUser(request).onComplete {
case Success(Some(user)) =>
println("user verified")
Results.Ok("user verified")
case Success(None) =>
println("user does not exist")
Results.Ok("user does not exist")
case Failure(f) =>
println("unknown error")
Results.Ok("unknown error")
}
}
}
Now you can test your api as below
def main(args: Array[String]): Unit = {
import Api._
httpLayer(UUID.randomUUID().toString) // user verified
}
Note1: you might want to use api to respond Future[Either[Error, User]] to better handle errors and use Error to determine what to respond back to the http consumers.
Note2: Since you are working with two monads Future[Option[a]], you can combine them using Monad Transformation OptionT[OuterMonad, Value Type] in scalaz or cats mtl library. Which gives a single monad OptionT.
def verifyUserV2(tokenString: String)(implicit executionContext: ExecutionContext) = {
import scalaz._
import Scalaz._
// import cats.implicits._
// import cats.data.OptionT
val userStack = for {
token <- OptionT(userTokenRepo.find(UserTokenKey(UUID.fromString(tokenString))))
user <- OptionT(userRepo.findUser(token.loginInfo))
updatedUser <- OptionT(userRepo.updateUser(user))
removedUser <- OptionT(userTokenRepo.remove(UserTokenKey(UUID.fromString(tokenString))))
} yield removedUser
userStack.run
//cats unpack stack
// userStack.value
}
Useful reads:
Futures - map vs flatmap
Using Either to process failures in Scala code

closing file pointer in Scala in Finally

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
}
}

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)
})
}

Implement Actor model without Akka in Scala

I am doing my small research that implement Actor without Akka
I found one implementation of Actor in Scala. (How to implement actor model without Akka?)
It's very simple. Because I have not enough reputation to add the comment, so I create this question.
I wonder if I use Actor like below.
1/ How can I shutdown that actor from main thread?
2/ How can I add feature similar to Akka, like parent actor, kill request, and become method?
import scala.concurrent._
trait Actor[T] {
implicit val context = ExecutionContext.fromExecutor(java.util.concurrent.Executors.newFixedThreadPool(1))
def receive: T => Unit
def !(m: T) = Future { receive(m) }
}
This is my own example when trying to adapt the above code snippet
import scala.concurrent._
/**
* Created by hminle on 10/21/2016.
*/
trait Message
case class HelloMessage(hello: String) extends Message
case class GoodByeMessage(goodBye: String) extends Message
object State extends Enumeration {
type State = Value
val Waiting, Running, Terminating = Value
}
trait Actor[T] {
implicit val context = ExecutionContext.fromExecutor(java.util.concurrent.Executors.newFixedThreadPool(1))
private var state: State.State = State.Waiting
def handleMessage: T => Unit ={
if(state == State.Waiting) handleMessageWhenWaiting
else if(state == State.Running) handleMessageWhenRunning
else handleMessageWhenTerminating
}
def !(m: T) = Future {handleMessage(m)}
def handleMessageWhenWaiting: T => Unit
def handleMessageWhenRunning: T => Unit
def handleMessageWhenTerminating: T => Unit
def transitionTo(destinationState: State.State): Unit = {
this.state = destinationState
}
}
class Component1 extends Actor[Message]{
def handleMessageWhenRunning = {
case HelloMessage(hello) => {
println(Thread.currentThread().getName + hello)
}
case GoodByeMessage(goodBye) => {
println(Thread.currentThread().getName + goodBye)
transitionTo(State.Terminating)
}
}
def handleMessageWhenWaiting = {
case m => {
println(Thread.currentThread().getName + " I am waiting, I am not ready to run")
transitionTo(State.Running)
}
}
def handleMessageWhenTerminating = {
case m => {
println(Thread.currentThread().getName + " I am terminating, I cannot handle any message")
//need to shutdown here
}
}
}
class Component2(component1: Actor[Message]) extends Actor[Message]{
def handleMessageWhenRunning = {
case HelloMessage(hello) => {
println(Thread.currentThread().getName + hello)
component1 ! HelloMessage("hello 1")
}
case GoodByeMessage(goodBye) => {
println(Thread.currentThread().getName + goodBye)
component1 ! GoodByeMessage("goodbye 1")
transitionTo(State.Terminating)
}
}
def handleMessageWhenWaiting = {
case m => {
println(Thread.currentThread().getName + " I am waiting, I am not ready to run")
transitionTo(State.Running)
}
}
def handleMessageWhenTerminating = {
case m => {
println(Thread.currentThread().getName + " I am terminating, I cannot handle any message")
//need to shutdown here
}
}
}
object ActorExample extends App {
val a = new Component1
val b = new Component2(a)
b ! HelloMessage("hello World 2")
b ! HelloMessage("hello World 2, 2nd")
b ! GoodByeMessage("Good bye 2")
println(Thread.currentThread().getName)
}
You can look at Actor model implementation in scalazand take ideas from it, source code in scalaz actor is easier for insight than akka. You have freedom of choice about architecture: you can use mailboxes based on ConcurrentLinkedQueue like in Akka, use CAS for AtomicReffernce like in scalaz, in your case you use Future mechanism. IMO, you must write a context of your actor system, so solve first and second items in your question it's the variant of ActorContext:
val contextStack = new ThreadLocal[List[ActorContext]]
and shutdown can look like this:
1.
case Kill ⇒ throw new ActorKilledException("Kill")
case PoisonPill ⇒ self.stop()
2. For storing parent actor and similar task, you must store reference on them:
def parent: ActorRef
it's hard to say about advantages of every technique (CAS, mailboxes), it's possible variants to your research.

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!