Retrofit Iterable to extend AutoCloseable
Brian Goetz
brian.goetz at oracle.com
Tue Nov 22 10:11:49 PST 2011
And then extending foreach to also support Iterator? This was a design
decision made by the JSR-201 EG for a reason -- that it would be too
"side-effecty" to have
for (T t : it) { ... }
drain the values out of 'it'.
Because you do want to be able to say:
for (String s : reader.lines()) { ... }
On 11/22/2011 12:58 PM, Sam Pullara wrote:
> I'm ok with using Iterator in this case. Why wouldn't all the same extension methods be available on it? I could imagine
>
> interface File {
> Iterable<String> lines() default { ... }
> }
>
> Since presumably that could be re-iterated.
>
> Sam
>
> On Nov 22, 2011, at 9:15 AM, Brian Goetz wrote:
>
>> More generally, how far we can stretch Iter{ator,able} to cover things
>> like IO ops, which are not simply views of existing finite-sized
>> aggregates (collections, arrays) is an open question. For example, it
>> would be nice if we could add something like this to Reader:
>>
>> interface Reader {
>> ...
>> Iterable<String> lines() default { ... }
>> }
>>
>> Note that this is probably better than the obvious:
>>
>> interface Reader {
>> ...
>> void eachLine(Block<String>) default { ... }
>> }
>>
>> because by returning an Iterable, you then have easy access to the
>> extension methods of Iterable like filter(), map(), and friends; you can
>> say:
>>
>> List<String> nonEmptyLines = reader.lines()
>> .filter(s -> !s.isEmpty())
>> .into(new ArrayList<>());
>>
>> whereas with an eachLine method, you'd have to do it more imperatively.
>>
>> But this is a funky kind of Iterable for two reasons:
>> - Iterating it might throw exceptions
>> - You can only iterate it once.
>>
>> The latter issue is the killer, because we have been for 15 years
>> encouraging the notion that you can iterate an Iterable multiple times.
>>
>> Options:
>> - Introduce IterableOnce as a subtype of Iterable. This has good
>> doc-value, and easily picks up the extension methods from Iterable, but
>> does not play no nicely with the LiskovSubstitutionPrinciple.
>> - Introduce IterableOnce as a supertype of Iterable. This arguably
>> plays better with the LSP (since can-iterate-many is-a
>> can-iterate-once), but requires more thought to understand.
>>
>> Neither is all that attractive.
>>
>> The exception issue similarly offers some options:
>> - Adopt exception transparency. The design we've got for ET is OK,
>> but not great, requires a lot more thought, and we haven't come across
>> all that many cases (like this one) where it's needed.
>> - Wrap exceptions. Not great, but probably OK here.
>>
>> On 11/22/2011 11:37 AM, Reinier Zwitserloot wrote:
>>> Having the 'owner' instance autoclose its iterables/itself on GC also
>>> wouldn't be backwards compatible (in that lots of code is out there today
>>> that doesn't start closing resources on GC).
>>>
>>> We'd also have to retrofit the extended for loop (for (String x :
>>> iterable)) to call close at the end and then have to answer hairy questions
>>> like the distinction between Iterable and Iterator (which one is supposed
>>> to get the close() method? Tough question!).
>>>
>>> This is a pretty big step that would require lots of further research,
>>> though my gut instinct tells me its not a feasible option due primarily due
>>> significant backwards compatibility issues. Even introducing a new subtype
>>> (ClosableIterable or some such) will cause backwards compatibility issues
>>> because the JVM does not treat 2 methods with the same name and parameter
>>> types equal if the return type is different. AutoClosable is a supertype in
>>> many places and that _DOES_ work for backwards compatibility, that's the
>>> key. (And the trywith construct is entirely new, so a lot less to worry
>>> about for backwards compatibility!).
>>>
>>> Lastly, the JVM already has destructors; it's called Object.finalize(),
>>> though you could write an entire book on how relying on them is a horrible
>>> idea and how their mere existence really gets in the way of a lot of GC
>>> optimizations. If memory serves, any object with a non-empty finalize
>>> method gets special (slow) treatment to make it work. That solution is
>>> therefore also unlikely to be the right answer.
>>>
>>> --Reinier Zwitserloot
>>>
>>>
>>>
>>> On Tue, Nov 22, 2011 at 1:33 AM, Zhong Yu<zhong.j.yu at gmail.com> wrote:
>>>
>>>> I think this is very different from adding some helper methods on
>>>> collection interfaces.
>>>>
>>>> Adding close() to Iterator significantly changes how the interface
>>>> should be used. Old code ignorant of the close() method would now
>>>> become incorrect.
>>>>
>>>> We can remedy this by requiring that any subclass with a non-trivial
>>>> close() must arrange to effectively trigger close() when the object is
>>>> GC-ed. However this is not an easy thing to do. (Maybe JDK can help us
>>>> here by providing a "destructor" utility like `void onGC(object,
>>>> action)`
>>>>
>>>> Zhong Yu
>>>>
>>>> On Mon, Nov 21, 2011 at 12:18 PM, Cleber Muramoto
>>>> <cleber at nightcoders.com.br> wrote:
>>>>> I've been following the list for a while, but I couldn't find any mention
>>>>> about this.
>>>>>
>>>>> I think it would be interesting for Iterable/Iterator to extend
>>>>> AutoCloseable providing a default no-op close(), allowing, for example,
>>>> the
>>>>> creation Iterables backed by IO resources without the need to expose
>>>>> neither a specific interface nor the IO resource itself.
>>>>>
>>>>> Of course it would be much cooler if we had python-like yielders! But I
>>>>> think that this poor's man solution would suffice for a variety of use
>>>>> cases.
>>>>>
>>>>> Regards.
>>>>>
>>>>> Cleber.
>>>>>
>>>>>
>>>>
>>>>
>>>
>>
>
More information about the lambda-dev
mailing list