Issues with generic type detection of SAM types implemented using lambdas
Oliver Gierke
ogierke at pivotal.io
Thu Jan 11 16:47:43 UTC 2018
Yes, and no. You basically argue we're discussing the same things, immediately describing two *different* things being discussed:
1. There's a difference between instances of a generic type and anonymous (or plain implementation) classes and that has always been the case. Essentially "new ArrayList<String>();" VS "new ArrayList<String>() {}" (mind the curly braces).
Yes. That's correct. Nobody is disputing that. We can assume Java developers being familiar with that distinction. There's no one arguing the two are exchangeable in terms of generics resolution.
2. There's a difference between Lambdas and anonymous classes. The former are widely presented as equivalent of the latter
*That* is my point. As I see every other week, in contrast to the one above, not a lot of Java developers are familiar with *that* difference and caught by surprise.
Function<Integer, String> lambdaFunction = i -> i.toString();
Function<Integer, String> oldschoolFunction = new Function<Integer, String>() {
public String apply(Integer t) {
return t.toString();
}
};
Basically, 2 is invalidating 1 *if* we assume that the expressions in 2 are equivalent and virtually *every* resource around lambdas on the web suggest that they are. The upper right side (i -> …) is supposed to be a direct replace for the lower (new Function<…) and thus both variants fall onto the right side of my example in 1, when in fact they do not.
"The lower is creating type information to allow generics resolution" -> "The upper is equivalent to the lower" -> "The upper is creating type information to allow generics resolution". You might think that's crazily naive to assume that as you're all familiar with the complex intrinsics of all of that but it seems to be a very common source of confusion.
Anyway, I guess I've made my point an we're just gonna have to agree to disagree here :).
Cheers,
Ollie
> Am 11.01.2018 um 17:08 schrieb elias vasylenko <eliasvasylenko at gmail.com>:
>
> I don't think you are discussing different things at all, Oliver.
>
> You have presented your argument from two points of view:
>
> - Users can't pass lambdas to methods unless they know for sure that the implementation isn't relying on being able to reflect over generic type parameters.
>
> - As a result, library implementors / API designers can't rely on generic type information being available.
>
> David's point is that both of these statements were already true for regular classes before lambdas came along.
>
> What difference does it make if you have one more special case you need your users to avoid? Either you already properly document these awkward restrictions of argument types where it is not obvious and deem it an acceptable risk, in which case you only need to make a minor change to this documentation, or your API was already broken.
>
> On Thu, 11 Jan 2018 at 15:34 Oliver Gierke <ogierke at pivotal.io> wrote:
> Again, I think we're discussing different things here. You refer to the fact that from an instance of a generic class, without creating an anonymous subtype, there's no way to find out about the generic type they've been bound to. That's fine and - I guess - common knowledge amongst Java developers.
>
> I am looking a different case and thus a different problem: Lambdas have been advertised as a direct alternative to anonymous classes (see [0], esp. section 12), and that's the reason IDEs unconditionally recommend to convert the latter into the former. However, for a given generic interface, reflecting over the declared generics in the Lambda variant behaves fundamentally different compared to an anonymous implementation.
>
> So I am pretty passionless on whether that's "trying to be clever" or "bad". I was merely pointing out an inconsistency.
>
> Cheers,
> Ollie
>
> [0] http://cr.openjdk.java.net/~briangoetz/lambda/lambda-state-final.html
>
> > Am 11.01.2018 um 15:20 schrieb David Lloyd <david.lloyd at redhat.com>:
> >
> > On Thu, Jan 11, 2018 at 8:03 AM, Oliver Gierke <ogierke at pivotal.io> wrote:
> >>> Am 11.01.2018 um 14:56 schrieb David Lloyd <david.lloyd at redhat.com>:
> >>>
> >>> On Thu, Jan 11, 2018 at 3:10 AM, Oliver Gierke <ogierke at pivotal.io> wrote:
> >>>> Lambda based implementations of SAM types currently don't support inspecting the type for generic type parameters. This can cause unexpected surprise...
> >>>
> >>> Here's a non-lambda example that demonstrates that inspecting *any*
> >>> class for generic type parameters is fragile and not a good idea:
> >>>
> >>> public final class Hasher<T> implements ToIntFunction<T> {
> >>> int applyAsInt(T value) { return value.hashCode(); }
> >>> }
> >>>
> >>> Oops, now all my concrete implementations have generic parameters.
> >>
> >> I'm afraid I can't follow.
> >
> > Your example code which prints the actual type arguments will fail
> > because there is no actual type argument declared on the generic
> > *type*, only the *instance*. If you create an API which relies on
> > getting actual types off of an object instance's class, you've made a
> > usability mistake.
> >
> >>> Telling users they cannot have generic parameters on their
> >>> implementation classes is poor API design.
> >>
> >> Who is actually doing that?
> >
> > "I just wanted to point out that an ordinary user -- in general client
> > code that uses APIs with SAM types -- *has to implicitly know* whether
> > *any code* (potentially Java 6 based) downstream might attempt
> > generics resolution before she can decide whether to use a Lambda with
> > this SAM type."
> >
> > Anyone who wrote one of these APIs is actually doing that. It has
> > nothing to do with lambdas, and everything to do with APIs relying on
> > the assumption that implementation classes will have actual values for
> > every type parameter that it may inherit. This assumption is flawed
> > because it's completely normal for a user to have a single function
> > implementation that works for many types; this is a solid
> > memory-conserving technique. The only thing broken by this are
> > "clever" APIs that require usage of getActualTypeArguments() to get
> > necessary information from the user.
> >
> > --
> > - DML
>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: Message signed with OpenPGP
URL: <http://mail.openjdk.java.net/pipermail/compiler-dev/attachments/20180111/3e189036/signature-0001.asc>
More information about the compiler-dev
mailing list