Using `try`/`finally` without `catch`

Code screenshots are rather suboptimal, in particular for those participating in this forum via the email interface. Some self-contained, standalone code demonstrating the issue plus the corresponding compiler output, both in text form, thus accessible to copy&paste, would be much more useful for anybody who would like to help, IMHO.

Using is not a replacement for try/finally. It is a mechanism for running a code block that operates on a “closable” resource and ensures that the resource is closed after the block completes, likely using try/catch/finally under the hood. See the API docs for details. In your scenario, the kind of resource management covered by the Using API would rather be encapsulated within #write() and/or #openImageFile(), the resource being a file writer/reader, stream or similar.

Just as an aside, the logic here feels somewhat odd to start with. You attempt to write a file and then, no matter whether the attempt succeeded, you want to open it…? :thinking:

I see your point. This is indeed an unfortunate distraction when using try/finally. The code is not intending to try something and whether or not it fails to then do something else. The code is really just intending to evaluate two expressions and return the value of the first one.
Indeed when evaluating the two expressions, I’d ideally like to fail if either fails.
So I agree that try/finally is far from ideal, and even misleading to the reader.

What I think I need is something like the following from lisp/scheme. But I don’t think there’s any human-readable idiom for this in Scala.

def prog1[A,B](a:A,b:B):A = a

Well, that depends on the human, I guess. :smirk:

I’m not aware of any such functionality for “plain” types in the standard API (and I’ve never missed it). But nothing keeps you from putting this approach into your toolkit - I’d just name it #andThen() or similar, rather than #prog1(). :slight_smile: And perhaps I’d wrap it up as a method and make it explicit that the second argument is evaluated after the first.

implicit class AndThen[A <: Any](val a: A) extends AnyVal {
  def andThen[B](b: => B): A = {
    b
    a
  }
}

println(42.andThen("b"))
println(({ throw new IllegalStateException() }: Int).andThen("b"))

This functionality is provided for where side effects are managed explicitly - there is Future#andThen().

println(Await.result(Future { 42 }.andThen { case _ => "b" }, 1 second))
println(Await.result(Future[Int] { throw new IllegalStateException() }.andThen { case _ => "b" }, 1 second))

[EDIT: Future#andThen() probably is not a good example, as the argument to #andThen() is not supposed to have side effects - this should rather be

for { a <- futA ; _ <- futB } yield a

or the like.]

…and with cats-effect’s IO, there’s the Applicative API.

println((IO(42) <* IO("b")).unsafeRunSync())
println((IO[Int] { throw new IllegalStateException() } <* IO("b")).unsafeRunSync())
1 Like

Yes, I would indeed like to create a library of common utilities which I can use across different projects.
Until now, I’ve just been copying the functions 1 by 1 as I need them.

I’m looking into the LIBRARY AUTHOR GUIDE documentation, but it is still not exactly clear to me how to do this.

In Scala 2.13, after import util.chaining._ you can:

scala 2.13.3> 3.tap(x => println(x * 2))
6
val res2: Int = 3

or if you don’t care about the value, which makes it like prog1:

scala 2.13.3> 3.tap(_ => println("hi"))
hi
val res3: Int = 3

personally, most of the time I would probably just write:

val a = ...
b
a

and leave it at that.

1 Like