Re: Ability to decorate ChangeListener

2014-03-24 Thread Martin Sladecek

Mario,
thanks for your suggestion, but I think your specific case will not 
justify the change. First of all, as it was already said, equals should 
be symmetric. Knowing the implementation, you could rely on the fact 
that either the equals is called on the provided listener or on the 
listeners already in the list. Might be that somebody else would need 
the asymmetry to be implemented in the listener provided to 
removeListener() method and the current situation suits him, so why do 
the change for your case?


Anyway, relying on some implementation-specific behaviour is generally a 
sign of bad code practice, so it should give you a hint that you should 
find a different solution (like the one you discussed with Tomas 
already). It might happen that the code would be changed / re-factored 
in the future or some bug would be fixed there and behaviour will change 
again, breaking your application in some future JFX version.


Regards,
-Martin


On 22.3.2014 15:47, Mario Ivankovits wrote:

The only thing which I ask for is to flip this „if in the *ExpressionHelper 
classes:
So, JavaFX does not break anything and it is up to the app developer to take 
the risk or not.


if (listener.equals(changeListeners[index])) {

If we flip this to

if (changeListeners[index].equals(listener))



Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

If you are talking about a change to the JavaFX API, we are not likely to 
accept such a change if it breaks the contract of equals() or hashcode(). In 
your own app it may not matter, but it is dangerous to assume it won't matter 
to anyone. Martin owns the core libraries and can comment further.

-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same 
HashSet/Map …. for sure - but why should they?

 @Override
 public boolean equals(Object obj)
 {
 return obj == delegate; //  this == obj
 }

 @Override
 public int hashCode()
 {
 return delegate.hashCode();
 }


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:



A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

interface Subscription {
void unsubscribe();
}

class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

Subscription sub = observableValue.subscribe(listener);
// ...
sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at wrote:


Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

if (listener.equals(changeListeners[index])) {

If we flip this to

if 

Re: Ability to decorate ChangeListener

2014-03-24 Thread Mario Ivankovits
Thanks for your answer!

One thing, I think, we can agree on, is that it is overly complex for an OO 
language to decorate things like these listeners.
What about introducing another interface like ChangeListenerDecoration with a 
special named „boolean decorates(ChangeListener)) method and call this if the 
listeners hold by *ExpressionHelp class implements that interface?

BTW: If we care about symmetry, why not change the 
listener.equals(otherListener) to listener == otherListener at all? Then, there 
are not implementation details one can make use of.
I even might argue that it is a security risk to use the .equals() the way it 
is now, as an evil listener implementation is able to remove all listeners from 
the list by simply returning true from equals()
It should be the responsibility of the listener in the list to know if the 
passed in listener justify the removal of itself, right? … from a security 
standpoint! :-) 

Regards,
Mario


Am 24.03.2014 um 07:31 schrieb Martin Sladecek martin.slade...@oracle.com:

 Mario,
 thanks for your suggestion, but I think your specific case will not justify 
 the change. First of all, as it was already said, equals should be symmetric. 
 Knowing the implementation, you could rely on the fact that either the equals 
 is called on the provided listener or on the listeners already in the list. 
 Might be that somebody else would need the asymmetry to be implemented in the 
 listener provided to removeListener() method and the current situation 
 suits him, so why do the change for your case?
 
 Anyway, relying on some implementation-specific behaviour is generally a sign 
 of bad code practice, so it should give you a hint that you should find a 
 different solution (like the one you discussed with Tomas already). It might 
 happen that the code would be changed / re-factored in the future or some bug 
 would be fixed there and behaviour will change again, breaking your 
 application in some future JFX version.
 
 Regards,
 -Martin
 
 
 On 22.3.2014 15:47, Mario Ivankovits wrote:
 The only thing which I ask for is to flip this „if in the *ExpressionHelper 
 classes:
 So, JavaFX does not break anything and it is up to the app developer to take 
 the risk or not.
 
 
if (listener.equals(changeListeners[index])) {
 
 If we flip this to
 
if (changeListeners[index].equals(listener))
 
 
 
 Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
 kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:
 
 If you are talking about a change to the JavaFX API, we are not likely to 
 accept such a change if it breaks the contract of equals() or hashcode(). In 
 your own app it may not matter, but it is dangerous to assume it won't 
 matter to anyone. Martin owns the core libraries and can comment further.
 
 -- Kevin
 
 
 Mario Ivankovits wrote:
 
 Hi Thomas!
 
 Thanks for your input. Because I want to decorated listeners added by JavaFX 
 core I can not use the sub/unsub pattern.
 Your second proposal is almost what I do right now. In removeListener I 
 consult a map where the decorated listeners and their undecorated one lives.
 
 Regarding the symmetric doubts. Such listeners will always be removed by 
 passing in the undecorated object to removeListener.
 They should act like a transparent proxy.
 
 Even if this breaks the equals paradigm, in this special case I can 
 perfectly live with an equals/hashCode implementation like this below.
 It won’t break your app; as long as both objects do not live in the same 
 HashSet/Map …. for sure - but why should they?
 
 @Override
 public boolean equals(Object obj)
 {
 return obj == delegate; //  this == obj
 }
 
 @Override
 public int hashCode()
 {
 return delegate.hashCode();
 }
 
 
 Regards,
 Mario
 
 
 Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
 tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:
 
 
 
 A simpler and more universal solution is to also override removeListener:
 
 public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
 }
 
 And the equals() method on decorated listeners only compares the
 delegates (thus is symmetric).
 
 Regards,
 Tomas
 
 
 On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
 tomas.mik...@gmail.commailto:tomas.mik...@gmail.com wrote:
 
 
 The suspicious thing about your solution is that your smart
 implementation of equals() is not symmetric.
 
 In case the observable value is visible only within your project, you
 could do this:
 
interface Subscription {
void unsubscribe();
}
 
class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}
 
 and use subscribe()/unsubscribe() instead of 

Re: Ability to decorate ChangeListener

2014-03-24 Thread Martin Sladecek

On 24.3.2014 15:24, Mario Ivankovits wrote:

But, after this discussion I do not see why one ever used .equals() at all.

Look, it does not fit my needs, I do not see any use-case where one would add 
an removeListener with asymmetric .equals() and thus it is better you use == I 
think.
This clarifies that EXACTLY the added listener instance is required to remove 
any listener AND it gives no room to discussions like we had because the 
indention is perfectly clear - even to those reading JavaFX core code and bug 
fixing things in JavaFX.
For me this would be fine and understandable - I will go the 
decorator-cache-map so I will be fine always.


One example might be in bidirectional binding. There's a special 
listener that takes the 2 properties that are bound together and it's 
equals returns true if the other listener is of the same class and it's 
two properties (no matter in what order) are identical. This way, you 
can just write Bindings.unbindBidirectional() and the internal 
implementation does not need to remember the listener instance anywhere. 
The equals() is symmetric in this case, but == would not work here.


-Martin


Re: Ability to decorate ChangeListener

2014-03-24 Thread Mario Ivankovits

Am 24.03.2014 um 15:36 schrieb Martin Sladecek martin.slade...@oracle.com:

 On 24.3.2014 15:24, Mario Ivankovits wrote:
 But, after this discussion I do not see why one ever used .equals() at all.
 
 Look, it does not fit my needs, I do not see any use-case where one would 
 add an removeListener with asymmetric .equals() and thus it is better you 
 use == I think.
 This clarifies that EXACTLY the added listener instance is required to 
 remove any listener AND it gives no room to discussions like we had because 
 the indention is perfectly clear - even to those reading JavaFX core code 
 and bug fixing things in JavaFX.
 For me this would be fine and understandable - I will go the 
 decorator-cache-map so I will be fine always.
 
 One example might be in bidirectional binding. There's a special listener 
 that takes the 2 properties that are bound together and it's equals returns 
 true if the other listener is of the same class and it's two properties (no 
 matter in what order) are identical. This way, you can just write 
 Bindings.unbindBidirectional() and the internal implementation does not need 
 to remember the listener instance anywhere. The equals() is symmetric in this 
 case, but == would not work here.
 
 -Martin

Ah - Thanks for this lesson!
:-)

OMG … just looked up the code. The implementation of BidirectionalBinding uses 
weak references and it might happen that you ExpressionHelperBase.trim() them 
out of the listener list if either side of the bound property got garbage 
collected.
This means, if I decorated them, they will stay in my map because there is 
add/removeListener asymmetry. (just to use the word symmetry again ;-) )

So, it is even more complicated to decorate that stuff.
How much I’d love to see a DecoratedListener interface like you have for 
WeakListener … but yay … :-(


Thanks for listening anyway! :-)

Regards,
Mario

Re: Ability to decorate ChangeListener

2014-03-24 Thread Tomas Mikula
On Mon, Mar 24, 2014 at 3:24 PM, Mario Ivankovits ma...@datenwort.at wrote:
 Hi Tomas!

 No worries, I’ll go the way on my own there then.


 But, after this discussion I do not see why one ever used .equals() at all.

 Look, it does not fit my needs, I do not see any use-case where one would add 
 an removeListener with asymmetric .equals() and thus it is better you use == 
 I think.

As Martin pointed out, sometimes == doesn't work for you and you need
(symmetric) equals(). Another example is my proposed solution #2 to
your problem.
Also, using equals instead of identity comparison is consistent with
how Collection.remove() determines equality.

 This clarifies that EXACTLY the added listener instance is required to remove 
 any listener AND it gives no room to discussions like we had because the 
 indention is perfectly clear - even to those reading JavaFX core code and bug 
 fixing things in JavaFX.
 For me this would be fine and understandable - I will go the 
 decorator-cache-map so I will be fine always.


 BTW: There are always implementation details one has to assume. For example, 
 I have to assume that the internals will always use the add/removeListener 
 methods and not modifying the list (or whatever) directly.
 There is something which we need to hold on - even if there is no 
 documentation for things like this.
 Any yay, if you patch some JavaFX core stuff, you will get deeper insights 
 and do not need to assume anymore, you KNOW how it works. Sometimes it is not 
 easy to misuse things then to get your job done! ;-)


 Also, if there is a risk in there current implementation it does not help 
 killing the discussion with the argument that there are other risks too.
 I am pretty well aware about stuff like that.


 PS: I would love to explain in detail why I decorate change listener, but 
 this is out of scope of this thread.

 Regards,
 Mario


 Am 24.03.2014 um 14:04 schrieb Tomas Mikula tomas.mik...@gmail.com:

 Hi Mario,

 On Mon, Mar 24, 2014 at 8:46 AM, Mario Ivankovits ma...@datenwort.at wrote:
 Thanks for your answer!

 One thing, I think, we can agree on, is that it is overly complex for an OO 
 language to decorate things like these listeners.

 I'm curious why you need to decorate the listeners in the first place.

 What about introducing another interface like ChangeListenerDecoration with 
 a special named „boolean decorates(ChangeListener)) method and call this if 
 the listeners hold by *ExpressionHelp class implements that interface?

 If you are writing your own ObservableValue implementation, you can as
 well implement your own ExpressionHelper that does whatever you want
 (just that you don't forget this option ;-)).

 BTW: If we care about symmetry, why not change the 
 listener.equals(otherListener) to listener == otherListener at all? Then, 
 there are not implementation details one can make use of.
 I even might argue that it is a security risk to use the .equals() the way 
 it is now, as an evil listener implementation is able to remove all 
 listeners from the list by simply returning true from equals()
 It should be the responsibility of the listener in the list to know if the 
 passed in listener justify the removal of itself, right? … from a security 
 standpoint! :-)

 You cannot secure your application at this level. An evil listener
 might as well introduce memory leaks, cause stack overflow, or wipe
 out your hard disk.

 Tomas


 Regards,
 Mario


 Am 24.03.2014 um 07:31 schrieb Martin Sladecek martin.slade...@oracle.com:

 Mario,
 thanks for your suggestion, but I think your specific case will not 
 justify the change. First of all, as it was already said, equals should be 
 symmetric. Knowing the implementation, you could rely on the fact that 
 either the equals is called on the provided listener or on the listeners 
 already in the list. Might be that somebody else would need the asymmetry 
 to be implemented in the listener provided to removeListener() method 
 and the current situation suits him, so why do the change for your case?

 Anyway, relying on some implementation-specific behaviour is generally a 
 sign of bad code practice, so it should give you a hint that you should 
 find a different solution (like the one you discussed with Tomas already). 
 It might happen that the code would be changed / re-factored in the future 
 or some bug would be fixed there and behaviour will change again, breaking 
 your application in some future JFX version.

 Regards,
 -Martin


 On 22.3.2014 15:47, Mario Ivankovits wrote:
 The only thing which I ask for is to flip this „if in the 
 *ExpressionHelper classes:
 So, JavaFX does not break anything and it is up to the app developer to 
 take the risk or not.


   if (listener.equals(changeListeners[index])) {

 If we flip this to

   if (changeListeners[index].equals(listener))



 Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
 

Re: Ability to decorate ChangeListener

2014-03-24 Thread Stephen F Northover
I'm pretty sure this discussion has solidified around not flipping the 
equals() but this is a good example of something that we wouldn't 
change.  If you write code that relies on this, it will break in the 
future when new code is added in FX that does not follow the pattern.


Steve

On 2014-03-22 10:47 AM, Mario Ivankovits wrote:

The only thing which I ask for is to flip this „if in the *ExpressionHelper 
classes:
So, JavaFX does not break anything and it is up to the app developer to take 
the risk or not.


if (listener.equals(changeListeners[index])) {

If we flip this to

if (changeListeners[index].equals(listener))



Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

If you are talking about a change to the JavaFX API, we are not likely to 
accept such a change if it breaks the contract of equals() or hashcode(). In 
your own app it may not matter, but it is dangerous to assume it won't matter 
to anyone. Martin owns the core libraries and can comment further.

-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same 
HashSet/Map …. for sure - but why should they?

 @Override
 public boolean equals(Object obj)
 {
 return obj == delegate; //  this == obj
 }

 @Override
 public int hashCode()
 {
 return delegate.hashCode();
 }


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:



A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

interface Subscription {
void unsubscribe();
}

class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

Subscription sub = observableValue.subscribe(listener);
// ...
sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at wrote:


Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

if (listener.equals(changeListeners[index])) {

If we flip this to

if (changeListeners[index].equals(listener)) {

a listener decoration can be smart enough to not only check against itself, but 
also against its delegate.

What do you think?

I could prepare a patch for the *ExpressionHelper classes.


Best regards,
Mario











Re: Ability to decorate ChangeListener

2014-03-22 Thread Tomas Mikula
The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

interface Subscription {
void unsubscribe();
}

class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

Subscription sub = observableValue.subscribe(listener);
// ...
sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at wrote:
 Hi!

 In one of my ObservableValue implementations I do have the need to decorate 
 ChangeListener added to it.
 Today this is somewhat complicated to implement, as I have to keep a map of 
 the original listener to the decorated one to being able to handle the 
 removal process of a listener. Because the outside World did not know that I 
 decorated the listener and the instance passed in to removeListener ist the 
 undecorated one.

 We can make things easier with a small change in 
 ExpressionHelper.removeListener. When iterating through the listener list, 
 the listener passed in as argument to removeListener is asked if it is equal 
 to the one stored

 if (listener.equals(changeListeners[index])) {

 If we flip this to

 if (changeListeners[index].equals(listener)) {

 a listener decoration can be smart enough to not only check against itself, 
 but also against its delegate.

 What do you think?

 I could prepare a patch for the *ExpressionHelper classes.


 Best regards,
 Mario




Re: Ability to decorate ChangeListener

2014-03-22 Thread Tomas Mikula
A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula tomas.mik...@gmail.com wrote:
 The suspicious thing about your solution is that your smart
 implementation of equals() is not symmetric.

 In case the observable value is visible only within your project, you
 could do this:

 interface Subscription {
 void unsubscribe();
 }

 class MyObservableValueT implements ObservableValueT {
 public Subscription subscribe(ChangeListener? extends T listener) {
 ChangeListenerT decorated = decorate(listener);
addListener(decorated);
return () - removeListener(decorated);
 }
 }

 and use subscribe()/unsubscribe() instead of addListener()/removeListener():

 Subscription sub = observableValue.subscribe(listener);
 // ...
 sub.unsubscribe();

 Of course this is not possible if you need to pass the observable
 value to the outside world as ObservableValue.

 Regards,
 Tomas

 On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at wrote:
 Hi!

 In one of my ObservableValue implementations I do have the need to decorate 
 ChangeListener added to it.
 Today this is somewhat complicated to implement, as I have to keep a map of 
 the original listener to the decorated one to being able to handle the 
 removal process of a listener. Because the outside World did not know that I 
 decorated the listener and the instance passed in to removeListener ist the 
 undecorated one.

 We can make things easier with a small change in 
 ExpressionHelper.removeListener. When iterating through the listener list, 
 the listener passed in as argument to removeListener is asked if it is equal 
 to the one stored

 if (listener.equals(changeListeners[index])) {

 If we flip this to

 if (changeListeners[index].equals(listener)) {

 a listener decoration can be smart enough to not only check against itself, 
 but also against its delegate.

 What do you think?

 I could prepare a patch for the *ExpressionHelper classes.


 Best regards,
 Mario




Re: Ability to decorate ChangeListener

2014-03-22 Thread Mario Ivankovits
Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same 
HashSet/Map …. for sure - but why should they? 

@Override
public boolean equals(Object obj)
{
return obj == delegate; //  this == obj
}

@Override
public int hashCode()
{
return delegate.hashCode();
}


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula tomas.mik...@gmail.com:

 A simpler and more universal solution is to also override removeListener:
 
 public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
 }
 
 And the equals() method on decorated listeners only compares the
 delegates (thus is symmetric).
 
 Regards,
 Tomas
 
 
 On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula tomas.mik...@gmail.com wrote:
 The suspicious thing about your solution is that your smart
 implementation of equals() is not symmetric.
 
 In case the observable value is visible only within your project, you
 could do this:
 
interface Subscription {
void unsubscribe();
}
 
class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}
 
 and use subscribe()/unsubscribe() instead of addListener()/removeListener():
 
Subscription sub = observableValue.subscribe(listener);
// ...
sub.unsubscribe();
 
 Of course this is not possible if you need to pass the observable
 value to the outside world as ObservableValue.
 
 Regards,
 Tomas
 
 On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at wrote:
 Hi!
 
 In one of my ObservableValue implementations I do have the need to decorate 
 ChangeListener added to it.
 Today this is somewhat complicated to implement, as I have to keep a map of 
 the original listener to the decorated one to being able to handle the 
 removal process of a listener. Because the outside World did not know that 
 I decorated the listener and the instance passed in to removeListener ist 
 the undecorated one.
 
 We can make things easier with a small change in 
 ExpressionHelper.removeListener. When iterating through the listener list, 
 the listener passed in as argument to removeListener is asked if it is 
 equal to the one stored
 
if (listener.equals(changeListeners[index])) {
 
 If we flip this to
 
if (changeListeners[index].equals(listener)) {
 
 a listener decoration can be smart enough to not only check against itself, 
 but also against its delegate.
 
 What do you think?
 
 I could prepare a patch for the *ExpressionHelper classes.
 
 
 Best regards,
 Mario
 
 



Re: Ability to decorate ChangeListener

2014-03-22 Thread Kevin Rushforth
If you are talking about a change to the JavaFX API, we are not likely 
to accept such a change if it breaks the contract of equals() or 
hashcode(). In your own app it may not matter, but it is dangerous to 
assume it won't matter to anyone. Martin owns the core libraries and can 
comment further.


-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same HashSet/Map …. for sure - but why should they? 


@Override
public boolean equals(Object obj)
{
return obj == delegate; //  this == obj
}

@Override
public int hashCode()
{
return delegate.hashCode();
}


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula tomas.mik...@gmail.com:

  

A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
   super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula tomas.mik...@gmail.com wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

   interface Subscription {
   void unsubscribe();
   }

   class MyObservableValueT implements ObservableValueT {
   public Subscription subscribe(ChangeListener? extends T listener) {
   ChangeListenerT decorated = decorate(listener);
  addListener(decorated);
  return () - removeListener(decorated);
   }
   }

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

   Subscription sub = observableValue.subscribe(listener);
   // ...
   sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at wrote:
  

Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

   if (listener.equals(changeListeners[index])) {

If we flip this to

   if (changeListeners[index].equals(listener)) {

a listener decoration can be smart enough to not only check against itself, but 
also against its delegate.

What do you think?

I could prepare a patch for the *ExpressionHelper classes.


Best regards,
Mario





  


Re: Ability to decorate ChangeListener

2014-03-22 Thread Mario Ivankovits
The only thing which I ask for is to flip this „if in the *ExpressionHelper 
classes:
So, JavaFX does not break anything and it is up to the app developer to take 
the risk or not.


   if (listener.equals(changeListeners[index])) {

If we flip this to

   if (changeListeners[index].equals(listener))



Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

If you are talking about a change to the JavaFX API, we are not likely to 
accept such a change if it breaks the contract of equals() or hashcode(). In 
your own app it may not matter, but it is dangerous to assume it won't matter 
to anyone. Martin owns the core libraries and can comment further.

-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same 
HashSet/Map …. for sure - but why should they?

@Override
public boolean equals(Object obj)
{
return obj == delegate; //  this == obj
}

@Override
public int hashCode()
{
return delegate.hashCode();
}


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:



A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
   super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

   interface Subscription {
   void unsubscribe();
   }

   class MyObservableValueT implements ObservableValueT {
   public Subscription subscribe(ChangeListener? extends T listener) {
   ChangeListenerT decorated = decorate(listener);
  addListener(decorated);
  return () - removeListener(decorated);
   }
   }

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

   Subscription sub = observableValue.subscribe(listener);
   // ...
   sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at wrote:


Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

   if (listener.equals(changeListeners[index])) {

If we flip this to

   if (changeListeners[index].equals(listener)) {

a listener decoration can be smart enough to not only check against itself, but 
also against its delegate.

What do you think?

I could prepare a patch for the *ExpressionHelper classes.


Best regards,
Mario









Re: Ability to decorate ChangeListener

2014-03-22 Thread Mario Ivankovits
Yep, null throws a NullPointerException in addListener by design (also in 
removeListener) - the listener collection is safe.



Am 22.03.2014 um 15:50 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

What if changeListeners[index] is null? Maybe this is already illegal

Anyway, let's see what Martin has to say. In the mean time you file a JIRA 
enhancement request (issuetype=Tweak) if you like.

-- Kevin


Mario Ivankovits wrote:
The only thing which I ask for is to flip this „if in the *ExpressionHelper 
classes:
So, JavaFX does not break anything and it is up to the app developer to take 
the risk or not.


   if (listener.equals(changeListeners[index])) {

If we flip this to

   if (changeListeners[index].equals(listener))



Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

If you are talking about a change to the JavaFX API, we are not likely to 
accept such a change if it breaks the contract of equals() or hashcode(). In 
your own app it may not matter, but it is dangerous to assume it won't matter 
to anyone. Martin owns the core libraries and can comment further.

-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX 
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I consult 
a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by 
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can perfectly 
live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same 
HashSet/Map …. for sure - but why should they?

@Override
public boolean equals(Object obj)
{
return obj == delegate; //  this == obj
}

@Override
public int hashCode()
{
return delegate.hashCode();
}


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:



A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
   super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

   interface Subscription {
   void unsubscribe();
   }

   class MyObservableValueT implements ObservableValueT {
   public Subscription subscribe(ChangeListener? extends T listener) {
   ChangeListenerT decorated = decorate(listener);
  addListener(decorated);
  return () - removeListener(decorated);
   }
   }

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

   Subscription sub = observableValue.subscribe(listener);
   // ...
   sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at wrote:


Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

   if (listener.equals(changeListeners[index])) {

If we flip this to

   if (changeListeners[index].equals(listener)) {

a listener decoration can be smart enough to not only check against itself, but 
also against its delegate.

What do you think?

I could prepare a patch for the *ExpressionHelper classes.


Best regards,
Mario










Re: Ability to decorate ChangeListener

2014-03-22 Thread Tomas Mikula
Hi Mario,

even if your proposal gets accepted, you would still depend on an
implementation detail of JavaFX, which is always good to avoid.

To sum up, my second proposal compared to your current solution:

(+) your equals() stays symmetric;
(+) no need for an extra Map of listeners.

My second proposal compared to your desired solution if your proposal
is accepted:

(+) your equals() stays symmetric;
(+) you don't depend on an implementation detail in JavaFX.

Best,
Tomas

On Sat, Mar 22, 2014 at 3:47 PM, Mario Ivankovits ma...@datenwort.at wrote:
 The only thing which I ask for is to flip this „if in the *ExpressionHelper
 classes:
 So, JavaFX does not break anything and it is up to the app developer to take
 the risk or not.

if (listener.equals(changeListeners[index])) {

 If we flip this to

if (changeListeners[index].equals(listener))




 Am 22.03.2014 um 15:42 schrieb Kevin Rushforth kevin.rushfo...@oracle.com:

 If you are talking about a change to the JavaFX API, we are not likely to
 accept such a change if it breaks the contract of equals() or hashcode(). In
 your own app it may not matter, but it is dangerous to assume it won't
 matter to anyone. Martin owns the core libraries and can comment further.

 -- Kevin


 Mario Ivankovits wrote:

 Hi Thomas!

 Thanks for your input. Because I want to decorated listeners added by JavaFX
 core I can not use the sub/unsub pattern.
 Your second proposal is almost what I do right now. In removeListener I
 consult a map where the decorated listeners and their undecorated one lives.

 Regarding the symmetric doubts. Such listeners will always be removed by
 passing in the undecorated object to removeListener.
 They should act like a transparent proxy.

 Even if this breaks the equals paradigm, in this special case I can
 perfectly live with an equals/hashCode implementation like this below.
 It won’t break your app; as long as both objects do not live in the same
 HashSet/Map …. for sure - but why should they?

 @Override
 public boolean equals(Object obj)
 {
 return obj == delegate; //  this == obj
 }

 @Override
 public int hashCode()
 {
 return delegate.hashCode();
 }


 Regards,
 Mario


 Am 22.03.2014 um 14:22 schrieb Tomas Mikula tomas.mik...@gmail.com:



 A simpler and more universal solution is to also override removeListener:

 public void removeListener(ChangeListener? super T listener) {
super.removeListener(decorated(listener));
 }

 And the equals() method on decorated listeners only compares the
 delegates (thus is symmetric).

 Regards,
 Tomas


 On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula tomas.mik...@gmail.com
 wrote:


 The suspicious thing about your solution is that your smart
 implementation of equals() is not symmetric.

 In case the observable value is visible only within your project, you
 could do this:

interface Subscription {
void unsubscribe();
}

class MyObservableValueT implements ObservableValueT {
public Subscription subscribe(ChangeListener? extends T listener) {
ChangeListenerT decorated = decorate(listener);
   addListener(decorated);
   return () - removeListener(decorated);
}
}

 and use subscribe()/unsubscribe() instead of addListener()/removeListener():

Subscription sub = observableValue.subscribe(listener);
// ...
sub.unsubscribe();

 Of course this is not possible if you need to pass the observable
 value to the outside world as ObservableValue.

 Regards,
 Tomas

 On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at
 wrote:


 Hi!

 In one of my ObservableValue implementations I do have the need to decorate
 ChangeListener added to it.
 Today this is somewhat complicated to implement, as I have to keep a map of
 the original listener to the decorated one to being able to handle the
 removal process of a listener. Because the outside World did not know that I
 decorated the listener and the instance passed in to removeListener ist the
 undecorated one.

 We can make things easier with a small change in
 ExpressionHelper.removeListener. When iterating through the listener list,
 the listener passed in as argument to removeListener is asked if it is equal
 to the one stored

if (listener.equals(changeListeners[index])) {

 If we flip this to

if (changeListeners[index].equals(listener)) {

 a listener decoration can be smart enough to not only check against itself,
 but also against its delegate.

 What do you think?

 I could prepare a patch for the *ExpressionHelper classes.


 Best regards,
 Mario









Re: Ability to decorate ChangeListener

2014-03-22 Thread Mario Ivankovits
Probably you avoid the map, but it requires to decorate the listener again, 
right?
If you think about the tons of observable values and add/removeListener 
operations in an tree view when scrolling it might get costly and put pressure 
on the GC.

Anyway, I will be more than happy to assist with a cleaner solution by 
introduction an interface like DecoratedChangeListener which provides a special 
.equalsChangeListener(ChangeListener other) method.


Am 22.03.2014 um 15:55 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:

Hi Mario,

even if your proposal gets accepted, you would still depend on an
implementation detail of JavaFX, which is always good to avoid.

To sum up, my second proposal compared to your current solution:

(+) your equals() stays symmetric;
(+) no need for an extra Map of listeners.

My second proposal compared to your desired solution if your proposal
is accepted:

(+) your equals() stays symmetric;
(+) you don't depend on an implementation detail in JavaFX.

Best,
Tomas

On Sat, Mar 22, 2014 at 3:47 PM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at wrote:
The only thing which I ask for is to flip this „if in the *ExpressionHelper
classes:
So, JavaFX does not break anything and it is up to the app developer to take
the risk or not.

  if (listener.equals(changeListeners[index])) {

If we flip this to

  if (changeListeners[index].equals(listener))




Am 22.03.2014 um 15:42 schrieb Kevin Rushforth 
kevin.rushfo...@oracle.commailto:kevin.rushfo...@oracle.com:

If you are talking about a change to the JavaFX API, we are not likely to
accept such a change if it breaks the contract of equals() or hashcode(). In
your own app it may not matter, but it is dangerous to assume it won't
matter to anyone. Martin owns the core libraries and can comment further.

-- Kevin


Mario Ivankovits wrote:

Hi Thomas!

Thanks for your input. Because I want to decorated listeners added by JavaFX
core I can not use the sub/unsub pattern.
Your second proposal is almost what I do right now. In removeListener I
consult a map where the decorated listeners and their undecorated one lives.

Regarding the symmetric doubts. Such listeners will always be removed by
passing in the undecorated object to removeListener.
They should act like a transparent proxy.

Even if this breaks the equals paradigm, in this special case I can
perfectly live with an equals/hashCode implementation like this below.
It won’t break your app; as long as both objects do not live in the same
HashSet/Map …. for sure - but why should they?

   @Override
   public boolean equals(Object obj)
   {
   return obj == delegate; //  this == obj
   }

   @Override
   public int hashCode()
   {
   return delegate.hashCode();
   }


Regards,
Mario


Am 22.03.2014 um 14:22 schrieb Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com:



A simpler and more universal solution is to also override removeListener:

public void removeListener(ChangeListener? super T listener) {
  super.removeListener(decorated(listener));
}

And the equals() method on decorated listeners only compares the
delegates (thus is symmetric).

Regards,
Tomas


On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula 
tomas.mik...@gmail.commailto:tomas.mik...@gmail.com
wrote:


The suspicious thing about your solution is that your smart
implementation of equals() is not symmetric.

In case the observable value is visible only within your project, you
could do this:

  interface Subscription {
  void unsubscribe();
  }

  class MyObservableValueT implements ObservableValueT {
  public Subscription subscribe(ChangeListener? extends T listener) {
  ChangeListenerT decorated = decorate(listener);
 addListener(decorated);
 return () - removeListener(decorated);
  }
  }

and use subscribe()/unsubscribe() instead of addListener()/removeListener():

  Subscription sub = observableValue.subscribe(listener);
  // ...
  sub.unsubscribe();

Of course this is not possible if you need to pass the observable
value to the outside world as ObservableValue.

Regards,
Tomas

On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits 
ma...@datenwort.atmailto:ma...@datenwort.at
wrote:


Hi!

In one of my ObservableValue implementations I do have the need to decorate
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of
the original listener to the decorated one to being able to handle the
removal process of a listener. Because the outside World did not know that I
decorated the listener and the instance passed in to removeListener ist the
undecorated one.

We can make things easier with a small change in
ExpressionHelper.removeListener. When iterating through the listener list,
the listener passed in as argument to removeListener is asked if it is equal
to the one stored

  if (listener.equals(changeListeners[index])) {

If we flip 

Re: Ability to decorate ChangeListener

2014-03-22 Thread Tomas Mikula
On Sat, Mar 22, 2014 at 4:11 PM, Mario Ivankovits ma...@datenwort.at wrote:
 Probably you avoid the map, but it requires to decorate the listener again,
 right?

Right. For a pair of addListener-removeListener calls, you have 2
decorations instead of 1. I usually think of the costs in asymptotic
terms: if 1 decoration is cheap, then 2 decorations are cheap as well.
Or, if we can afford n decorations, then we can probably afford 2n
decorations. I know this is not quite true in real world (200ms is not
the same as 100ms), but is a good way to think about complexity.

 If you think about the tons of observable values and add/removeListener
 operations in an tree view when scrolling it might get costly and put
 pressure on the GC.

removeListener creates one extra short-lived object. I don't know if
it is still true for the current garbage collector in Hotspot, but a
while ago I read that creating a lot of cheap short-lived objects is
fine for the GC.

Regards,
Tomas


 Anyway, I will be more than happy to assist with a cleaner solution by
 introduction an interface like DecoratedChangeListener which provides a
 special .equalsChangeListener(ChangeListener other) method.


 Am 22.03.2014 um 15:55 schrieb Tomas Mikula tomas.mik...@gmail.com:

 Hi Mario,

 even if your proposal gets accepted, you would still depend on an
 implementation detail of JavaFX, which is always good to avoid.

 To sum up, my second proposal compared to your current solution:

 (+) your equals() stays symmetric;
 (+) no need for an extra Map of listeners.

 My second proposal compared to your desired solution if your proposal
 is accepted:

 (+) your equals() stays symmetric;
 (+) you don't depend on an implementation detail in JavaFX.

 Best,
 Tomas

 On Sat, Mar 22, 2014 at 3:47 PM, Mario Ivankovits ma...@datenwort.at
 wrote:

 The only thing which I ask for is to flip this „if in the *ExpressionHelper
 classes:
 So, JavaFX does not break anything and it is up to the app developer to take
 the risk or not.

   if (listener.equals(changeListeners[index])) {

 If we flip this to

   if (changeListeners[index].equals(listener))




 Am 22.03.2014 um 15:42 schrieb Kevin Rushforth kevin.rushfo...@oracle.com:

 If you are talking about a change to the JavaFX API, we are not likely to
 accept such a change if it breaks the contract of equals() or hashcode(). In
 your own app it may not matter, but it is dangerous to assume it won't
 matter to anyone. Martin owns the core libraries and can comment further.

 -- Kevin


 Mario Ivankovits wrote:

 Hi Thomas!

 Thanks for your input. Because I want to decorated listeners added by JavaFX
 core I can not use the sub/unsub pattern.
 Your second proposal is almost what I do right now. In removeListener I
 consult a map where the decorated listeners and their undecorated one lives.

 Regarding the symmetric doubts. Such listeners will always be removed by
 passing in the undecorated object to removeListener.
 They should act like a transparent proxy.

 Even if this breaks the equals paradigm, in this special case I can
 perfectly live with an equals/hashCode implementation like this below.
 It won’t break your app; as long as both objects do not live in the same
 HashSet/Map …. for sure - but why should they?

@Override
public boolean equals(Object obj)
{
return obj == delegate; //  this == obj
}

@Override
public int hashCode()
{
return delegate.hashCode();
}


 Regards,
 Mario


 Am 22.03.2014 um 14:22 schrieb Tomas Mikula tomas.mik...@gmail.com:



 A simpler and more universal solution is to also override removeListener:

 public void removeListener(ChangeListener? super T listener) {
   super.removeListener(decorated(listener));
 }

 And the equals() method on decorated listeners only compares the
 delegates (thus is symmetric).

 Regards,
 Tomas


 On Sat, Mar 22, 2014 at 2:07 PM, Tomas Mikula tomas.mik...@gmail.com
 wrote:


 The suspicious thing about your solution is that your smart
 implementation of equals() is not symmetric.

 In case the observable value is visible only within your project, you
 could do this:

   interface Subscription {
   void unsubscribe();
   }

   class MyObservableValueT implements ObservableValueT {
   public Subscription subscribe(ChangeListener? extends T listener) {
   ChangeListenerT decorated = decorate(listener);
  addListener(decorated);
  return () - removeListener(decorated);
   }
   }

 and use subscribe()/unsubscribe() instead of addListener()/removeListener():

   Subscription sub = observableValue.subscribe(listener);
   // ...
   sub.unsubscribe();

 Of course this is not possible if you need to pass the observable
 value to the outside world as ObservableValue.

 Regards,
 Tomas

 On Sat, Mar 22, 2014 at 6:57 AM, Mario Ivankovits ma...@datenwort.at
 wrote:


 Hi!

 In one of my ObservableValue implementations I do have the need to 

Ability to decorate ChangeListener

2014-03-21 Thread Mario Ivankovits
Hi!

In one of my ObservableValue implementations I do have the need to decorate 
ChangeListener added to it.
Today this is somewhat complicated to implement, as I have to keep a map of the 
original listener to the decorated one to being able to handle the removal 
process of a listener. Because the outside World did not know that I decorated 
the listener and the instance passed in to removeListener ist the undecorated 
one.

We can make things easier with a small change in 
ExpressionHelper.removeListener. When iterating through the listener list, the 
listener passed in as argument to removeListener is asked if it is equal to the 
one stored

if (listener.equals(changeListeners[index])) {

If we flip this to

if (changeListeners[index].equals(listener)) {

a listener decoration can be smart enough to not only check against itself, but 
also against its delegate.

What do you think?

I could prepare a patch for the *ExpressionHelper classes.


Best regards,
Mario