Remi Forax forax at
Tue Jun 25 00:30:39 PDT 2013

On 06/25/2013 03:04 AM, Brian Goetz wrote:
> This note attempts to tie together the issues that have been raised 
> for streams having a resource release mechanism.  For an explanation 
> of why the initial attempt (which included the high-noise-to-signal 
> classes CloseableStream and DelegatingStream) was impractical, see 
> Paul's note here:
> and
> The key goals here are that we want to support both:
>  - Users who care about guaranteed resource release being able to 
> reliably do so unintrusively, without
>  - Users who don't care having to pay attention if they don't want to.
> Most of the problems we're discussing here are not new to streams; 
> they're a consequence of not having dealt sufficiently with resource 
> management in the past.
> For example, take the IO packages.  FileInputStream holds a 
> GC-resistent (GCR) resource, a file handle.  Therefore, well-behaved 
> code should ensure that it calls close() before the FIS goes out of 
> scope.  On the other hand, ByteArrayInputStream holds no GCR 
> resources, and in fact its close() method is documented to do nothing, 
> and you can even use the stream after closing it.
> Where things get nastier is when we attempt to abstract over these.  
> If you wrap a { FileInputStream, ByteArrayInputStream } with a 
> BufferedInputStream, what should BIS tell its users about whether 
> close() is needed or not?  The answer is that this information is not 
> easily captured in the static type system, and users have to reason 
> about what the BIS might be wrapping.  [1] Fortunately, the 
> consequences of either error (either closing it unnecessarily, or 
> failing to close it when there is a GCR resources there) are rarely 
> fatal.
> Streams are like BufferedInputStream, in that they might or might not 
> contain a GCR resource, except the default orientation is swapped: 
> most of the time, they do not, and failing to close them is just fine 
> (and actually encouraged).  But when they do, it is important to be 
> able to ensure that the resources held by underlying streams are 
> released. We want it to be POSSIBLE to ensure resources held by 
> streams are released, without users feeling forced to structure their 
> code around resource release in the many cases where they know no 
> resource needs to be released.
> The best tool we have for making sure resources are released is 
> try-with-resources.  Where possible, our resource management solution 
> should build on that, not compete with that.  That said, TWR is 
> imperfect.
> One imperfection is that when something is declared AutoCloseable, the 
> presumption seems to be that it *must* be closed, and this may put a 
> burden on user code.  For example, we don't want the situation where 
> users feel they have to do:
>   try (Stream s = {
>     s.forEach(...);
>   }
> instead of
>       .filter(...)
>       .map(...)
>       .forEach(...);

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 ?

A Stream is an abstraction over a loopy thing, so like in C#, the Stream 
should call close at the end if the source is an AutoCloseable.
Thus either the Spliterator takes care of the resource, but conceptually 
a Spliterator is more an abstraction over a traversal algorithm
or the Stream takes care of the resource.
Thus the solution is easy, instead of constructing a Stream with 2 
parameters, the supplier of spliterator and the characteristics,
we need a third parameter, an AutoCloseable that may be null and in the 
implementation of all terminal methods of Stream,
we have to enclose the 'loop' over the spliterator inside a TWR.

Sometimes the simple solution is the best one.

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