2

I want to have some utilities to use and cleanup a resource, safely and unsafely, and clean up the resource after use, somewhat equivalent to a try/finally, allowing for cleanup even if the operation throws an exception.

I have

def withResource[R, U](create: => R, cleanup: R => Unit)(op: R => U): U = {
  val r = create
  val res = op(r)
  cleanup(r)
  res
}

def tryWithResource[R, U](create: => R, cleanup: R => Unit)(op: R => U): Try[U] = {
  val tried: (R => Try[U]) = (r: R) => Try.apply(op(r))
  withResource(create, cleanup)(tried)
}

but I don't like

val tried: (R => Try[U]) = (r: R) => Try.apply(op(r))

It seems i'm missing some obvious composition function, but I can't see where. I tried

val tried: (R => Try[U]) = (Try.apply _).compose(op)

but that fails typecheck with

type mismatch;
[error]  found   : R => U
[error]  required: R => => Nothing
[error]     val tried: (R => Try[U]) = (Try.apply _).compose(op)

What am I missing/doing wrong?

Martijn
  • 11,964
  • 12
  • 50
  • 96
  • 1
    Just out of curiosity: why do you not like `Try.apply(op(r))` or shorter `Try(op(r))`? Sure, `(Try.apply(_: U)) compose op)` looks fancy, but is there any benefit? – Sascha Kolberg Oct 06 '15 at 10:50
  • 1
    @SaschaKolberg I felt I was writing something that already exists in `compose`, and even though it's a fairly trivial function, writing it twice seemed wrong to me. Then when it didn't work, I wanted to know why. – Martijn Oct 06 '15 at 10:52
  • More the wanting to know why that the really wanting to have it differently tbh. – Martijn Oct 06 '15 at 10:53

2 Answers2

7

You can just use map

val tried: (R => Try[U]) = Try.apply(_).map(op)

http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.util.Try

Herrington Darkholme
  • 5,979
  • 1
  • 27
  • 43
  • Like this approach more than one of @PeterNeyens, because there's no extra parentheses around the `Try.apply`. And with alternative syntax for `apply`, namely `Try(_).map(op)`, it's even more concise. – Haspemulator Oct 06 '15 at 10:52
  • I also think `Try(_).map(op)` or just `(r: R) => Try(op(r))` looks nicer, but the OP seemed to want to use `compose`. – Peter Neyens Oct 06 '15 at 10:57
5

You can use a type ascription to limit the parameter you pass to Try.apply to U :

val tried = (Try.apply(_: U)) compose op
Peter Neyens
  • 9,770
  • 27
  • 33