Loose ends: Optional

Brian Goetz brian.goetz at oracle.com
Sun Jun 2 10:09:11 PDT 2013

>> 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.)  

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.  

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.  

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.  

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