views:

186

answers:

3

Let's assume this function:

def autoClosing(f: {def close();})(t: =>Unit) = {
    t
    f.close()
}

and this snippet:

val a = autoClosing(new X)(_)
a {
 println("before close")
}

is it possible to curry the first part? Something like:

val a = autoClosing(_) { println("before close") }

so that I could send the objects on which close should be performed, and have the same block executed on them?

+9  A: 

Yes, the snippet you have given works, as long as you give the type of the placeholder character.

Therefore, the code you are looking for is:

val a = autoClosing(_: {def close();}) { println("before close") }

which compiles and works as expected :).

A couple of notes:

  • You can make your life easier if you define a type alias for an AnyRef type having a close method, something like type Closeable = AnyRef {def close()}, or an appropriate interface.
  • The code snippet autoClosing(_: Closeable){ ... } is actually equivalent to the following expanded anonymous function: c: Closeable => autoClosing(c){ ... }. The wildcard character is just shorthand for a partially applied function. You need to give the type of the _ as the type inferer unfortunately cannot infer the type in this case.

Hope it helps,

-- Flaviu Cipcigan

Flaviu Cipcigan
Kind of verbose. Mersi :)
Geo
You're welcome. Added a couple of notes to expand my answer :). Unfortunately, the type inferer cannot infer the type of the wildcard here.
Flaviu Cipcigan
+3  A: 

Alternatively you can flip the parameters:

def flip[A1, A2, B](f: A1 => A2 => B): A2 => A1 => B = x1 => x2 => f(x2)(x1)

In your case:

val a = flip(autoClosing){ println("before close") }

Edit: I've added some braces to help the human parser:

def flip[A1, A2, B](f: (A1 => (A2 => B))): (A2 => (A1 => B)) = {
    x1 => (x2 => f(x2)(x1))
}

Flip converts a function (A1 => (A2 => B)) to (A2 => (A1 => B)).

scala> def x(x1 : Int)(x2 : Long) = 1.0 * x1 / x2
x: (Int)(Long)Double

scala> val f = flip(x)
f: (Long) => (Int) => Double = <function>

scala> val g = f(1)
g: (Int) => Double = <function>

scala> val h = g(2)
h: Double = 2.0

scala> x(1)(2)
res0: Double = 0.5
Thomas Jung
Can you explain that monster a bit? :)
Geo
I added some braces and sample code so see the partial application in action. Hope this helps.
Thomas Jung
+3  A: 

I'm happy to see so many people answering Scala questions nowadays. It does make it harder for me to come up with something, however. Here's an alternative to Flaviu's solution.

val a: {def close();} => Unit = autoClosing(_) { println("before close") }

Of course, the proper solution is to define autoClosing in a way compatible with how you are going to use it.

Daniel
I'm happy about that too :). I'm giving up Ruby for Scala ... it's got everything I wanted in a language.
Geo