Difference between using a lambda and an anonymous inner interface implementation [message #1823384] |
Wed, 25 March 2020 18:21  |
Eclipse User |
|
|
|
I've just experience a very strange problem concerning SWT listeners implemented using a lambda. Replacing it with an old-fashioned instance of an anonymous inner interface implementation fixed the problem, but the behaviour is supposed to be the same isn't it!?
The case is a form with a set of Button instances that I create in a loop. For each of them I add an SWT Listener that closes over a variable referring to the new Button. All the buttons are also stored in an array references by a field. Here's the program structure:
for (int i = 0; i < options.size(); i++) {
final Button button = new Button(parent, SWT.RADIO);
button.addListener(SWT.Selection, event -> {
...
});
this.buttons[i] = button;
}
The first time the selection event is triggered all is fine, inside the listener's body the button variable refers to the same button as in the buttons array and the event's widget field. However, in later instances of the form, with a new set of buttons, this is not the case! The closed over button variable refers to a button from an earlier for that's disposed, and it's not one of the buttons in the buttons array. When I look down the stack, I see that the listener activated by SWTs event loop is not the same one I see on the top of the stack, it looks more like the correct one. One thing I notice is that the listener is not identified by the normal inner class name ala someclass$1, instead it is a some large number. I assume this is because the lambda is compiled into dynamic invoke or something, so it just looks different.
Anyway, I change the above code to
for (int i = 0; i < options.size(); i++) {
final Button button = new Button(parent, SWT.RADIO);
button.addListener(SWT.Selection, new Listener() {
@Override
public void handleEvent(Event event) {
...
}
});
this.buttons[i] = button;
}
which if I understand it correctly should be equivalent, and now everything works as expected! The button variable closed over is the one I expect, the event object's widget field refers to the same Button instance as button refers to, the stack looks normal etc.
Anyone knows what's happening? Am I completely mistaken in how the lambda expression is supposed to be equivalent to the instance of the anonymous interface implementation?
BTW, I'm using SWT from 2018, version 3.107.20160611 and running on SE 8 [1.8.0_51]
[Updated on: Wed, 25 March 2020 18:25] by Moderator
|
|
|
Re: Difference between using a lambda and an anonymous inner interface implementation [message #1824322 is a reply to message #1823384] |
Mon, 13 April 2020 16:06  |
Eclipse User |
|
|
|
This article about Java Lambda Expression closure-like functionality confirms your experience as expected:
"Note that Java does not support true closures. A Java lambda cannot be created in a way that allows it to see changes in the environment in which it was instantiated. If you want to implement a closure that observes or makes changes to its environment, you should simulate it using a regular class."
Just use Glimmer for the View layer if you prefer terser more declarative closure syntax:
https://github.com/AndyObtiva/glimmer
Let Java handle the Model and Controller layers only instead. This is kind of like how we have web UI built in HTML not Java since it's more appropriate for it.
My 2 cents.
[Updated on: Mon, 13 April 2020 16:08] by Moderator
|
|
|
Powered by
FUDForum. Page generated in 0.02940 seconds