MumbleCloseable

Jim Mayer jim at pentastich.org
Tue Jun 25 11:43:18 PDT 2013


Sorry... I didn't mean to send the previous version...  Here's the
complete note:

For what it's worth, I like Remi's analysis.

(1) If the user allocates the GC-resistant resource then the user is
responsible for releasing it.
(2) If the stream implementation allocates the GC-resistant resource then
the stream library should release it.
(3) Have each terminal operation (collectors, foreach, etc.) run inside a
try/release and ALWAYS invoke close (which will be a noop in most cases).

Personally, I have no problem with making Stream implement MumbleCloseable,
but I would still want to terminal operations to close the stream.  Could
MumbleCloseable.close() be defined to be idempotent (like Closeable, but
not AutoCloseable)?  This would allow code like:

try (Stream<Whatever> s = funkyStreamExpression...) {
  ... do something that may, or may not, evaluate the stream...
}

The systems I work on need to run continuously for months at a time.  We
really can't afford to leak descriptors, so I care a lot about resource
management.

On a related note, in the code Brian posted Stream.java contains the
following:

 901     public static <T> Stream<T> concat(Stream<? extends T> a,
Stream<? extends T> b) {
 902         Objects.requireNonNull(a);
 903         Objects.requireNonNull(b);
 904
 905         @SuppressWarnings("unchecked")
 906         Spliterator<T> split = new Streams.ConcatSpliterator.OfRef<>(
 907                 (Spliterator<T>) a.spliterator(),
(Spliterator<T>) b.spliterator());
 908         Stream<T> stream = (a.isParallel() || b.isParallel())
 909                            ? StreamSupport.parallelStream(split)
 910                            : StreamSupport.stream(split);
 911         return stream.onClose(() -> { a.close(); b.close(); });
 912     }

To really be safe, line 911 needs to be more like:

        return stream.onClose({} -> try a.close() finally b.close(); });

The reason is that the 'close' method could still throw a RuntimeException
or an Error.

Jim


On Tue, Jun 25, 2013 at 2:37 PM, Jim Mayer <jim at pentastich.org> wrote:

> For what it's worth, I like Remi's analysis.
>
> (1) If the user allocates the GC-resistant resource then the user is
> responsible for releasing it.
> (2) If the stream implementation allocates the GC-resistant resource then
> the stream library should release it.
> (3) Have each terminal operation (collectors, foreach, etc.) run inside a
> try/release and ALWAYS invoke close (which will be a noop in most cases).
>
> Personally, I have no problem with making Stream implement
> MumbleCloseable, but I would still want to terminal operations to close the
> stream.  Could MumbleCloseable.close() be defined to be idempotent (like
> Closeable, but not AutoCloseable)?  This would allow code like:
>
> try (Stream<Whatever> s = funkyStreamExpression...) {
>   ... do something that may, or may not, evaluate the stream...
> }
>
> The systems I work on need to run continuously for months at a time.  We
> really can't afford to leak file descriptors, so I care a lot about
> resource management.
>
> On a related note, in the code Brian posted Stream.java contains the
> following:
>
>
>
> On Tue, Jun 25, 2013 at 9:46 AM, Remi Forax <forax at univ-mlv.fr> wrote:
>
>> On 06/25/2013 03:22 PM, Brian Goetz wrote:
>>
>>> As someone said one the lambda-dev mailing list, there is no TWR in C#
>>>> because close is called at the end of the for-each instruction.
>>>> Why do you want user to care about releasing resources manually if this
>>>> can be done automatically ?
>>>>
>>>
>>> Because it can't be.
>>>
>>> What happens if:
>>>  - no one executes a terminal op
>>>
>>
>> This should be flagged by IDEs as useless operation even if there is no
>> resource involved.
>> See my answer to Stephan Hermann.
>>
>>
>>   - a terminal op throws an exception
>>>
>>
>> There is a TWR in the code that loop over the Spliterator in the terminal
>> operation.
>>
>>
>>   - the user asks for an Iterator/Spliterator and doesn't exhaust it
>>>
>>
>> don't allow an escape hatch on stream that are constructed on an implicit
>> resource
>> (there is no such issue if the resource is explicit).
>>
>>
>>
>>> This is analogous the problem with IO streams, where:
>>>
>>>   InputStream is = ...
>>>   use(is);
>>>   is.close();
>>>
>>> isn't good enough; you want try-finally (or TWR) to ensure that cleanup
>>> happens.
>>>
>>
>> yes, if you explicitly use the InputStream, you have to use a TWR,
>> if you implicitly uses a resource, instead of using a leaking*
>> abstraction as you propose (all streams become AutoCloseable),
>> it's better in my opinion to do the TWR inside the terminal operation.
>>
>>
>>
>>> What you suggest increases the probability that the stream is closed,
>>> but doesn't guarantee it.
>>>
>>
>> if you open it and close it in the same terminal operation, there is no
>> leak.
>>
>>
>>  (It also is far more intrusive in the implementation.)
>>>
>>
>> yes, but I think it can be abstracted if you have a way to represent a
>> pair spliterator/resource.
>>
>> Rémi
>> *sorry for the pun
>>
>>
>


More information about the lambda-libs-spec-observers mailing list