Add Predicate.of(), Consumer.of(), etc. (original) (raw)

Remi Forax forax at univ-mlv.fr
Thu May 7 19:26:32 UTC 2015


On 05/06/2015 03:53 PM, Paul Sandoz wrote:

On May 6, 2015, at 1:58 PM, Attila Szegedi <attila.szegedi at oracle.com> wrote:

On May 6, 2015, at 12:37 PM, Paul Sandoz <paul.sandoz at oracle.com> wrote:

On May 2, 2015, at 11:31 PM, Remi Forax <forax at univ-mlv.fr> wrote:

Hi all, today, I stubble on a variant of JDK-8050818 [1], trying to call negate() on a lambda which is not yet a Predicate (due to target typing) which requires either to cast the lambda to a Predicate and everybody knows that cast are evil or to add a local variable.

I think there is a way to fix that, it's not very orthodox so I let you judge. The idea is to introduce a static method 'of' on Predicate, class Predicate { ... public static Predicate of(Predicate predicate) { return predicate; } } so one can write: stream.filter(Predicate.of(String::isEmpty).negate()) compared to stream.filter(((Predicate)String::isEmpty).negate()) so the question is, does it it worth the cost to introduce a static method that basically do nothing on all functional interfaces of java.util.function. That does have the virtue of not adding a static method per operation but i still cannot bring myself to add such methods as a work around for seems like a compiler inference problem (albeit one in which might be very tricky or not possible to solve). I think it is firmly in the category of “very tricky”, but probably still possible, albeit (from my point of view) undesirable. String::isEmpty will not, on its own, have a method named .negate(); the compiler can’t really infer the programmer’s intent to make it into a Predicate, not without a fairly high level reasoning (filter needs a Predicate; should the compiler perform an exhaustive search of the visible functional interfaces to see which one has a method with signature “Predicate negate()”?). So, yeah, it seems like in this case the programmer needs to communicate the intent. I think inference would be possible, but it’d be expensive, and would still allow for either ambiguities or accidentally matching something unexpected, so I think it would also be undesirable. Ok.

I agree with Atilla, basically, the compiler can only infer the function type corresponding to a lambda so the compiler need to bridge the gap between the function type and the corresponding interface by using some vodoo incantation based on the types currently imported (at least).

I don’t have an opinion of whether we want an “of” static method on Predicate, as then it would have to indeed be introduced on many other interfaces. It’s more appealing than a cast, certainly; especially since the cast apparently needs to specify the explicit type parameter too. I guess it's too late to consider an implicitly declared method along the lines of what Remi suggests. FWIW i always found such methods on enum a little too magical.

about values() and valueOf(), the main issue for my students is that these methods have no javadoc.

And perhaps it's too confusing to consider an invocation mode where "this" can be an implicit first parameter.

The opposite of the C# extension method, write an instance method and you can use it as a static method, funny until someone will see when debugging that a call to a static method can run a method deep in the hierarchy :(

In some respects i wonder if the default methods on the functional interfaces are an attractive nuisance.

Function composition is an important concept and being able to specify an implementation of an operation on a function is exactly what a default method on a functional interface is, by example:

interface Logger { void log(String msg); default Logger filter(Predicate filter) { return msg -> { if (filter.accept(msg) { log(msg); } }; } }

// a Logger Logger logger = System.err::println; // a Logger that logs only message that starts with 'W' Logger wLogger = logger.filter(msg -> msg.startsWith("W"));

Meaning, if .negate(Predicate) were a static method on the Predicate class instead of a default method, then stream.filter(Predicate.negate(String::isEmpty)) would be possible? Yeah…

Yeah. We are now in the unfortunate position where to alleviate this problem we might require duplicate static and default methods. I have been sitting on the issue a bit and nearly closed it a few times :-) Paul.

Rémi



More information about the core-libs-dev mailing list