On 05/06/2015 03:53 PM, Paul Sandoz wrote:
On May 6, 2015, at 1:58 PM, Attila Szegedi <attila.szeg...@oracle.com> wrote:
On May 6, 2015, at 12:37 PM, Paul Sandoz <paul.san...@oracle.com> wrote:
On May 2, 2015, at 11:31 PM, Remi Forax <fo...@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<T> {
...
public static <T> Predicate<T> of(Predicate<T> predicate) {
return predicate;
}
}
so one can write:
stream.filter(Predicate.of(String::isEmpty).negate())
compared to
stream.filter(((Predicate<String>)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<String> 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