Loose ends: Optional

Remi Forax forax at univ-mlv.fr
Sun Jun 2 12:17:29 PDT 2013

On 06/02/2013 07:09 PM, Brian Goetz wrote:
>>> The implementation decides if something can be lazy, I'm ok with these having the same methods. In fact, I suggest we change the name of isPresent to forEach.
>> No, it's not the implementation that decides, it's the spec. You can not realistically change the implementation of a method from lazy to eager and vice versa. It's the argument of Brian, the spec of Optional will say that the method filter of Optional is not lazy. But relying on people reading the documentation is something that you should not do (hint people don't read the spec). Or should do for your most important concept of the API, not for something as minor as Optional. For Optional, it should just work, without thinking too much.
> Laziness is, unfortunately, a mostly-dynamic property like immutability, thread-safety, or parallelism.  We don't have types for ImmutableList, ThreadSafeSet, or LazyCollection (and if we did, we'd have the explosion of LazyImmutableThreadSafeArrayDeque). These properties are generally propagated on projection; users expect a sublist of an immutable list to be immutable, or the keyset of a thread-safe map to be thread-safe, even though this is not always specified.
> Further, laziness always depends on some help from the implementation.  Is Iterator lazy?  Yes and no.  There's nothing that says an iterator cannot precompute more elements than have been requested, and many Iterators do just that (at least for the next element.)

Iterator is an interface. An implementation of an Iterator that filter 
another iterator is usually lazy
but if you ask an undergrad student to write that implementation it will 
be an eager.

> But, the extreme conclusion of the argument you are running is "there exists a lazy method called filter, so we cannot use filter for any non-lazy method" -- which is crazy.  We're not going let the existence of the eager Locale.filter keep Stream.filter from being lazy if it can.

You introduce the extreme conclusion yourself. I've never said that all 
methods named filter should be lazy.
I disagree that Optional should have a method named forEach or filter 
it means that Optional is an abstraction over a collection that have 
zero of one element.
Having an implementation of filter that is eager on an abstraction of a 
collection is a very bad idea.

> Bottom line: I think this "these methods are no good because they are eager" argument is not compelling.  And, I don't think users will find this confusing at all, if they understand something of what a Stream is and what an Optional is.

"these methods are no good because they are eager" on a collection-like object.

> The primary value of these methods is they enable fluent usage of common idioms.  The methods are simple, pure transformations, and their use does benefit from fluency.  They are the most frequently requested methods from the community in this entire exercise (so much so we've had to shut down debate on them on lambda-dev multiple times), and, while I don't particularly love them, I believe they are basically harmless.

They are harmful, by example, flatMap use a function that returns an 
if people use the same function in a stream, the result is collections 
of Optional, something we said we want to avoid.
As you said in an early mail Optional.map has a hidden cost at runtime, 
i will unbox/rebox the value for each call.

> So, let's pop this side-exploration of laziness-vs-eagerness off the stack and try and close on the merits.  The proposal stands at:
>   - filter, map, flatMap
>   - rename ifPresent to forEach


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