Review request for initial lambda functions and utils
Rémi Forax
forax at univ-mlv.fr
Wed Aug 10 06:22:38 PDT 2011
On 08/10/2011 12:54 AM, Kevin Bourrillion wrote:
> On Tue, Aug 9, 2011 at 3:32 PM, Rémi Forax <forax at univ-mlv.fr
> <mailto:forax at univ-mlv.fr>> wrote:
>
> Let's take an example, Predicates.compose is declared like this:
> <A,B> Predicate<A> compose(Predicate<B> predicate, Function<A, ?
> extends B> function)
>
> Basically, your signature works in most of the cases because
> you rely on the compiler to infer of A and B but there are some
> known cases
> by example if compose is called as a parameter of another method call
> where the inference is not done by the compiler.
>
>
> What we've tried to do is ensure that A and B can be inferred directly
> from the parameters given without having to rely on the method return
> value being directly assigned to a variable from which the type
> information could be gleaned.
>
> If the compiler don't do any inference, the easy workaround
> is to provide a type argument for A and for B,
> but with your API, it will not work.
>
> void foo(Predicate<String> p) { ... }
>
>
> You've lost me right there. That needs to be Predicate<? super String>.
>
> ...
> Predicate<String> p = ...
> Function<Object, String> f = ...
> foo(Predicates.compose(p, f)) // doesn't compile, Ok cf Java spec
>
>
> Just fix foo() and this works. No explicit type parameters needed.
Right, if you change the test case, the bug disappear !
More seriously, I don't control foo().
>
> It would be improper for compose(p, f) to return a Predicate<String>
> because a Predicate<Object> is /what it is/. It's a predicate that's
> capable of handling any object. There are very rare circumstances
> (well, rare when APIs are designed correctly) where you are forced to
> "pretend" that a Predicate is less capable than it really is.
> Cast-and-suppress is a perfectly reasonable escape valve for those
> situations.
I can't disagree more, it's a common pattern when you want to share lambdas.
Example, I want to share/reuse a projection function (your Function) to
take different types
knowing I will call toString() or hashCode() on the parameter of the
projection function,
I will define the function once taking an Object even if the resulting
Predicate
returns different types.
<T> Predicate<T> toStringCompose(Predicate<T> predicate) {
return Predicates.compose(predicate, TO_STRING_FUNCTION);
}
Another example, I have two classes A and B with B that inherits from A,
A defines a field (or a property). The projection function is defined to
take an A
and returns the value of the field. I can create a predicate on a A or
on a B,
I will not write the projection function twice, I will reuse the same
function
and compose to create a Predicate of A or B.
So it's perhaps you haven't seen these use cases because there is no
method reference
in Java but as you know it will change.
And I don't want to cast (and suppress) something i.e. add noise to my
program
just because you think everybody should not call your API by providing
the type
argument explicitly.
>
>
> foo(Predicates.<String,String>compose(p, f)) // doesn't compile
> too ??
>
>
>> but I can easily say that your compiler sounds like anything but
>> a /typical/ user project, which JDK APIs should be tailored to.
>
> An API should work :)
>
> Rémi
>
Rémi
More information about the lambda-dev
mailing list