this should not refer to the lambda
Peter Levart
peter.levart at gmail.com
Sun Feb 21 16:33:39 PST 2010
On Sunday 21 February 2010 23:28:35 Alex Blewitt wrote:
> On 21 Feb 2010, at 21:50, Peter Levart wrote:
> > #void(int) countdown = #(int i) { System.out.println(i); if(i>0)
> > countdown.(i-1) }
> >
> > ...could be defined as a special function typed variable initializer
> > (like for example array initializer). Plain and simple. No big deal.
>
> Right, so this would be 'disallow recursive case' option.
No, this would allow it - I was talking about the simple solution (not tackling the problems of
a more general solution that John Rose proposed where the right side could contain an arbitrary
function typed expression) - the array initializer was presented as an example of a syntax which
is contextually limited.
>
> > There is an implicit "this" which is much more important than explicit
> > "this".
> >
> > If you make "this" refer to the lambda instance (of function type) and
> > function types are reference types (subtypes of Object) then, to be
> > consistent, you must treat unqualified Object members (hashCode, equals,
> > wait*, notify*, getClass, toString) refer to the members of lambda
> > instance too.
>
> OK. That doesn't sound like a problem. After all, you can do those with
> arrays as well, right?
I don't understand you. You can do what with arrays? Did you mean array initializer?
"this" as well as unqualified Object method invocations inside array initializer refer to
enclosing class instance - not to array instance...
>
> > Code statistics computed by some participants of this list show that you
> > rarely need that in anonymous inner SAMs today.
>
> Rarely, but not never.
>
> > Quite the contrary, you often need to refer to
> > Object members of enclosing instance. By making it necessary to qualify
> > those references, you open the door to subtle bugs (some discovered just
> > by inspecting the places in JDK sources where qualified "this" was used,
> > see: http://mail.openjdk.java.net/pipermail/lambda-dev/2010-
> > February/000550.html).
>
> Agreed. But you can still refer to members of the enclosing instance using
> an explicit qualified this, as I've noted.
You can, but that's not the point. I was trying to present how often you would need to refer to
unqualified "this" representing lambda instance compared to how often you would need to refer to
unqualified Object methods representing methods of the enclosing class. Then I asserted that
these two "desires" are mutually exclusive. One of them has to be dropped. They both have a
workaround.
>
> > I doubt that Object methods would have any utility being invoked on
> > lambda instances:
>
> I agree with you. But then, they don't make any sense on arrays either.
They make more sense on arrays. But who's talking of arrays anyway?
>
> Note also that regardless of what 'this' is implemented as - or even if it
> refers to a MethodHandle - it will still be possible to invoke those
> methods on the reference type.
>
> #() foo = #() { };
>
> foo.toString();
> foo.wait(); //etc.
>
> int[] bar = {1,2,3};
> bar.toString();
> bar.wait(); // etc
Yes, but you missed the point again. I was trying to present that implicit "this" inside lambda
has no sense/utility as invoking Object methods on lambda instance is fruitless. I was not
comparing it to invoking Object methods on arrays. I was comparing it to invoking Object methods
on enclosing class which has more sense/utility.
>
> > On the contrary, they still have the same utility when invoked on an
> > enclosing object instance. By forcing the programmer to qualify them
> > (i.e. MyOuterClass.this.equals(...)) you have forced her to type more for
> > the majority of usecases.
>
> No, because I doubt that the majority of usecases will use Object-level
> methods on the enclosing object.
Compared to usecases of explicit "this" refering to lambda instance? I think yes. Remember?
We're comparing just those two mutually exclusive features.
> And for non-Object-level methods, you
> won't need to do this either.
You won't and you don't. What's the point?
> Arguably, a compiler warning of a
> self-reference to toString/equals etc. inside a lambda could be generated
> to warn in those cases where it's needed.
I don't think a warning is a solution for a badly designed feature.
>
> > More importantly, NO programmer is qualifying references to other
> > non-Object members of enclosing class (she is not a masochist is she?)
> > when she's writing the body of a single method of an anonymous inner SAM
> > instance. She's thinking in terms of outer class members at that time, so
> > she must be very careful not to select any of the inner's Object methods
> > by mistake.
>
> Your example of inner classes - where people are ware of these things
> already - fits well into the model where the lambda is the 'this' as well.
> The programmer will be thinking in those same terms should 'this' refer to
> the lambda.
Yes, and there's the catch. She'll be thinking in those terms, and forget about Object methods
being in scope and that refer to lambda's methods.
>
> > They work that way, because they are classes. With known syntactic
> > structure.
>
> And there's no (good) reason here posted yet as to why an equivalent
> conceptual model cannot work for lambdas, regardless of their
> implementation.
There are some good reasons I presented here. You just have to see them.
> > We can escape the metal jacket with them.
>
> What exactly, is the metal jacket?
http://en.wikipedia.org/wiki/Full_metal_jacket_bullet
The shape of classes is defined by their jacket - it can not be reformed. Lambdas can have their
own form - they are like hot lead at the moment - why are you trying to pour them into class'
jacket?
> I do not understand what kind of
> restrictions there are, or what cannot be done. Please enlighten me,
> because if there's something obvious I'm missing ... well, I'm missing it.
It's simple. Unqualified java.lang.Object method invocations must refer to the same instance as
unqualified "this". Not following this rule would render Java inconsistent. The desire to have
"this" refer to lambda instance conflicts with the desire to invoke (unqualified) Object methods
on enclosing class. We have to weight which of the two is more important. I think that
statistics presented so far show that invoking Object methods on enclosing class is more
frequent that referring to explicit "this" in anonymous inner SAM instances.
Which one to drop in lambdas? Both have a workaround.
>
> > I think I showed that "this" referring to lambda instance has a miniscule
> > usage compared to the usage of implicit unqualified "this" (references to
> > Object methods of enclosing instance). Tackling the problems of explicit
> > "this" and implicit "this" (unqualified Object methods) separately - i.e.
> > making "this" refer to lambda instance but unqualified Object methods
> > refer to enclosing class - would be a big mistake. It would simply be
> > inconsistent.
>
> It is just as arguable that using 'this' to refer to something other than
> its enclosing instance is inconsistent. The difference here is what the
> enclosing instance means. For a number of programmers used to inner
> classes, they may consider a lambda to work in the same way.
...until they are told that this is not so. They might be confused at first. They will have to
learn new rules (which are actually simpler). They will find that these rules make sense. And
they will like those rules. And finally they will applaud.
> But there is
> inconsistency in only permitting recursive lambdas by modifying the
> language structure such that in certain places, the LHS of an element can
> be defined with an assignment to a RHS which refers to the LHS.
This is positive inconsistency. An exception which allows something that is generally not
allowed. Positive in sense that you are positively surprised when you discover it.
Much better than negative inconsistency: an exception which prohibits something that is
generally allowed (arrays of function types?).
But the worst is irregular inconsistency: the same thing that has different meaning in two
different places:
synchronized (this) {
while (waiting) wait();
}
Regardless of what "this" refers to, the above idiom should work (not only compile) everywhere!
>
> Alex
>
Regards, Peter
More information about the lambda-dev
mailing list