Details

    • Type: New Feature
    • Status: Resolved
    • Priority: Major
    • Resolution: Fixed
    • Affects Version/s: 2.2.0-beta-2
    • Fix Version/s: 2.6.0-alpha-1
    • Component/s: Compiler
    • Labels:
      None

      Description

      Currently Groovy does not have an equivalent to Java 7's ARM blocks. The closest is adding a method which takes a closure to the class that you'd like to be auto-closed (or whatever gives you that resource), and implementing the closing logic in that method. This has a host of problems:

      • It's inefficient, requiring multiple method calls and an extra closure class over the Java solution
      • Since the closure-accepting methods are added ad-hoc, they have different names and quite possibly subtly different behaviour, particularly around what happens if an exception is thrown during the closing. By contrast this is well defined in Java 7 so a programmer doesn't have to go hunting for documentation or source code on the method that they're calling
      • If you are trying to work with an existing Java library rather than Groovy code, you're out of luck, since short of metaclass hacking you won't be able to add a wrapper method anyway

      It would also be nice to keep Groovy and Java syntax as consistent as possible to ease porting between the two.

        Activity

        Hide
        blackdrag Jochen Theodorou added a comment -

        That it is inefficient... well, if it is doing IO, the small overhead is not going to make a difference in reality.

        To mimic an Java7 arm block with a single resource, you actually need only one method in Groovy, but of course with an open block (resulting in a Closure). Multiple resources is where things in Groovy get hairy. It is of course possible to do multiple resources there as well, but the exception logic like the arm block is going to be quite difficult to implement in that method.

        That such a method could be added only by metaclass hacking... depends on how you define that. Any static method would do of course, but you could also use it as a category, maybe as extension method. For me a static method would be really just fine

        So we are a bit partial about adding this (the syntax is ugly for example)

        Show
        blackdrag Jochen Theodorou added a comment - That it is inefficient... well, if it is doing IO, the small overhead is not going to make a difference in reality. To mimic an Java7 arm block with a single resource, you actually need only one method in Groovy, but of course with an open block (resulting in a Closure). Multiple resources is where things in Groovy get hairy. It is of course possible to do multiple resources there as well, but the exception logic like the arm block is going to be quite difficult to implement in that method. That such a method could be added only by metaclass hacking... depends on how you define that. Any static method would do of course, but you could also use it as a category, maybe as extension method. For me a static method would be really just fine So we are a bit partial about adding this (the syntax is ugly for example)
        Hide
        russel Russel Winder added a comment -

        I agree the Java automated resource management (ARM), aka try with resources, is a bit ugly of syntax, however is it the Java expression of RAII, resource acquisition is initialization. Groovy already supports some "execute around" features on files etc. which obviates the need for explicit ARM. The question is whether Groovy should extend the execute around support to be much more general, currently it is quite specific to certain types, or to support the Java ARM somewhat.

        I am not particularly worried about exact Groovy syntax, but Groovy must support guaranteeing certain calls on specific objects in a block no matter how the block is exited.

        Show
        russel Russel Winder added a comment - I agree the Java automated resource management (ARM), aka try with resources, is a bit ugly of syntax, however is it the Java expression of RAII, resource acquisition is initialization. Groovy already supports some "execute around" features on files etc. which obviates the need for explicit ARM. The question is whether Groovy should extend the execute around support to be much more general, currently it is quite specific to certain types, or to support the Java ARM somewhat. I am not particularly worried about exact Groovy syntax, but Groovy must support guaranteeing certain calls on specific objects in a block no matter how the block is exited.
        Hide
        tomd Tom Dunstan added a comment -

        > That it is inefficient... well, if it is doing IO, the small overhead is not going to make a difference in reality.

        That's fine, but the use-case that drove me to look for this in Groovy and not find it was profiling, where overhead very much does matter.

        Ignoring the efficiency aspect (which is the least important to me, FWIW), we could indeed simply add a static method somewhere that could take a closure, and it wouldn't look too bad:

            withClosable(whatever.aquireThing()) {
                // do stuff
            }
        

        It could possibly even take multiple autoclosables:

            withClosable([whatever.aquireThing(), whatever.aquireAnotherThing()]) {
                // do stuff
            }
        

        or

            def thing1 = whatever.aquireThing()
            def thing2 = whatever.aquireAnotherThing()
            withClosable([thing1, thing2]) {
                // do stuff
            }
        

        The problem though, is what happens if whatever.aquireAnotherThing() throws an exception? The Java 7 compiler can handle this (see e.g the equivalent code generated in the Syntantic Sugar Demystified section of http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html), but we don't really have a good solution when using a static method except for nested blocks.

        I also am not mad about the Java syntax, in particular it forces you to define and give a name to the resource even if you don't reference it inside the block which makes things more verbose than they need to be (C# is better about this), but the full exception handling in different scenarios has been pretty well thought out, including allowing exceptions thrown inside the ARM code to be retrieved.

        Show
        tomd Tom Dunstan added a comment - > That it is inefficient... well, if it is doing IO, the small overhead is not going to make a difference in reality. That's fine, but the use-case that drove me to look for this in Groovy and not find it was profiling, where overhead very much does matter. Ignoring the efficiency aspect (which is the least important to me, FWIW), we could indeed simply add a static method somewhere that could take a closure, and it wouldn't look too bad: withClosable(whatever.aquireThing()) { // do stuff } It could possibly even take multiple autoclosables: withClosable([whatever.aquireThing(), whatever.aquireAnotherThing()]) { // do stuff } or def thing1 = whatever.aquireThing() def thing2 = whatever.aquireAnotherThing() withClosable([thing1, thing2]) { // do stuff } The problem though, is what happens if whatever.aquireAnotherThing() throws an exception? The Java 7 compiler can handle this (see e.g the equivalent code generated in the Syntantic Sugar Demystified section of http://www.oracle.com/technetwork/articles/java/trywithresources-401775.html ), but we don't really have a good solution when using a static method except for nested blocks. I also am not mad about the Java syntax, in particular it forces you to define and give a name to the resource even if you don't reference it inside the block which makes things more verbose than they need to be (C# is better about this), but the full exception handling in different scenarios has been pretty well thought out, including allowing exceptions thrown inside the ARM code to be retrieved.
        Hide
        blackdrag Jochen Theodorou added a comment -

        You could use more than one block, but as I said, mimicking what Java does here turns a bit ugly soon.

        I would be interested in knowing what you profiled, that made you think an ARM block con solve the problem. I mean it must be something about avoiding a Closure or else I don't see how an ARM block can speed things up. And even though creating a Closure is by far not for free, it must be a tight loop to show up significantly - and a tight loop with an ARM block looks to me special.. so I would like to know more.

        Show
        blackdrag Jochen Theodorou added a comment - You could use more than one block, but as I said, mimicking what Java does here turns a bit ugly soon. I would be interested in knowing what you profiled, that made you think an ARM block con solve the problem. I mean it must be something about avoiding a Closure or else I don't see how an ARM block can speed things up. And even though creating a Closure is by far not for free, it must be a tight loop to show up significantly - and a tight loop with an ARM block looks to me special.. so I would like to know more.
        Hide
        tomd Tom Dunstan added a comment -

        > You could use more than one block, but as I said, mimicking what Java does here turns a bit ugly soon.

        You mentioned syntax ugliness, which I partially agree with. I don't understand why implementing the Java behaviour is ugly in any other sense, though.

        > I would be interested in knowing what you profiled,

        No, I have a small Java library used for profiling (https://github.com/tomdcc/miniprofiler-jvm). In Java I can use ARM blocks for fairly fast profiling with little overhead added to the actual code. The overhead would be a little bit more in Groovy with closures, but honestly not that much compared to what we're expecting to be profiling (DB queries, etc).

        The "everything's a closure" mentality of Groovy can be a bit frustrating sometimes though, especially when you end up hitting memory limits when using frameworks like Grails on hosted systems like Heroku. PermGen isn't infinite, and since Java has shown how it's possible to do this without extra closure classes or closure instances, I didn't think asking for it would be a big deal. Maybe not a top priority, but not actually a feature from Java that got rejected. shrug

        Show
        tomd Tom Dunstan added a comment - > You could use more than one block, but as I said, mimicking what Java does here turns a bit ugly soon. You mentioned syntax ugliness, which I partially agree with. I don't understand why implementing the Java behaviour is ugly in any other sense, though. > I would be interested in knowing what you profiled, No, I have a small Java library used for profiling ( https://github.com/tomdcc/miniprofiler-jvm ). In Java I can use ARM blocks for fairly fast profiling with little overhead added to the actual code. The overhead would be a little bit more in Groovy with closures, but honestly not that much compared to what we're expecting to be profiling (DB queries, etc). The "everything's a closure" mentality of Groovy can be a bit frustrating sometimes though, especially when you end up hitting memory limits when using frameworks like Grails on hosted systems like Heroku. PermGen isn't infinite, and since Java has shown how it's possible to do this without extra closure classes or closure instances, I didn't think asking for it would be a big deal. Maybe not a top priority, but not actually a feature from Java that got rejected. shrug
        Show
        blackdrag Jochen Theodorou added a comment - An interesting discussion with regards to arm blocks http://stackoverflow.com/questions/12552863/correct-idiom-for-managing-multiple-chained-resources-in-try-with-resources-bloc
        Hide
        daniel_sun Daniel Sun added a comment -

        Fixed in the parrot branch

        Show
        daniel_sun Daniel Sun added a comment - Fixed in the parrot branch

          People

          • Assignee:
            daniel_sun Daniel Sun
            Reporter:
            tomd Tom Dunstan
          • Votes:
            4 Vote for this issue
            Watchers:
            8 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved:

              Development