2

I have come across what seems like a peculiarity in the JavaFX API: LongProperty implements Property<Number>, but not Property<Long>.

What is the reason for this? I sort of get the idea that it all stems from Java's inherent problem with covariance and contravariance, because generics where implemented stupidly via erasure, to maintain backwards compatibility with the bytecode; but what problem could have arisen by having LongProperty implement both Property<Number> and Property<Long>?

Edit: This question originated from this problem: Apply LongProperty to TableColumn programmatically (vs semantically)

Community
  • 1
  • 1
Itai
  • 6,641
  • 6
  • 27
  • 51
  • Hmm... I think I may have been too hasty to ask this question, seems like I don't fully understand Java's covariance and contravariance, so it may not be a problem at all. Sorry for that. – Itai Jan 05 '16 at 20:26
  • (Not presuming an answer here - just a question to @sillyfly). Long is a subclass of Number so wouldn't it inherently be implemented via it's parent class - maybe just requiring a cast? – Sam Jan 05 '16 at 20:27
  • 1
    I think it was a mistake. The design should have been something like `abstract class NumberProperty implements Property` and then `class IntegerProperty extends NumberProperty` etc. – James_D Jan 05 '16 at 20:30
  • This may have more to do with the way the `Property` methods are used. Something like this can exist as a feature rather than a mistake to allow for more permissive uses. Note that its other superinterfaces provide access as a `long`. – Radiodef Jan 05 '16 at 20:34
  • @Radiodef Well, yes, but now you can do `LongProperty lp = new SimpleLongProperty();`, `DoubleProperty dp = new SimpleDoubleProperty();` `dp.bindBidirectional(lp);` `dp.set(1.5);` and now you have `dp.getValue().equals(lp.getValue()) == false` even though they are bidirectionally bound. The inconsistency in the API is a worse evil than the lack of flexibility if they hadn't done it this way. (And remember, you can still instantiate `SimpleObjectProperty`, so you can bind observable objects containing numbers of any type using that mechanism.) – James_D Jan 05 '16 at 20:42
  • @James_D Like I said in my other comment, I'm more alarmed that I don't see the documentation immediately explaining what happens in such a case. Something like that could be programmed to behave in a reasonable way but we don't know except by testing it. – Radiodef Jan 05 '16 at 20:46

1 Answers1

4

It can't implement both.

To do that, it would need to implement two versions of each method in the interface that uses the generic. Let's take one as an example:

bindBidirectional(Property<Long> other) { ... }

Under the hood, erasure means this gets compiled down to:

bindBidirectional(Property other) { ... }

So then, what would something that implements Property<Number> and Property<Long> do? It would have two methods:

bindBidirectional(Property<Long> other) { ... }
bindBidirectional(Property<Number> other) { ... }

... that would compile down, after erasure, to two methods:

bindBidirectional(Property other) { ... }
bindBidirectional(Property other) { ... }

These two methods conflict, and there'd be no way to resolve them at runtime.

Even if you used some compiler trickery to get around this, what happens when someone uses LongProperty as a raw Property?

Property rawLongProperty = new LongProperty();
rawLongProperty.bindBidirectional(someOtherRawProperty);

There's no way to know which of the two bindDirectional variants this is meant to resolve to.

yshavit
  • 42,327
  • 7
  • 87
  • 124
  • Hmm... the same logic could be applied to argue that any `XYZProperty` should implement `Property`. How far up the inheritance tree do you go? Like I said, I think I need to read about it some more to understand it better, but like @James_D said above I suspect it may have been a design overlook. – Itai Jan 05 '16 at 20:32
  • 1
    @yshavit But do you really want to be able to do `LongProperty lp ;` `DoubleProperty dp` `dp.bindBidirectional(lp)`? This just doesn't seem like good API... – James_D Jan 05 '16 at 20:35
  • 1
    @sillyfly No, my point is just that it can only implement one `Property`. That something can be anything it wants -- Object, Long, Number, whatever -- but it it can't then implement `Property` as well. – yshavit Jan 05 '16 at 20:35
  • @James_D Well, one question at a time. :) The OP's question was as to why it didn't implement both, and that's what my answer was about. As to why it chose `Property` _instead of_ `Property`, that would be a different question (and one that I can't answer, since I'm not familiar with javafx). – yshavit Jan 05 '16 at 20:37
  • 1
    @yshavit Yes, fair enough. (Note, not my question.) But it is a design flaw :). – James_D Jan 05 '16 at 20:39
  • @James_D Some rounding would probably happen somewhere. I'm more like a fan of explicit casts so I don't particularly like it, but I don't really see a reason to say it's a flaw. I'm more alarmed that the documentation doesn't say what happens if you do that. – Radiodef Jan 05 '16 at 20:43
  • Yes, I understand now that it can't implement both. I guess now I really am interested in the reasons why one was chosen over the other. Should I edit my question to reflect this? Or make a new question? Or is it too opinion based? – Itai Jan 05 '16 at 20:47
  • I'm biased toward saying it'd be a new question, since I already answered the question as written. ;) But fair warning, questions about design decisions are _usually_ considered too opinion-based, unless you make it clear that you're looking for a definitive answer (like the designer chiming in, or someone finding an email thread where the decision was discussed) -- and even then, people may or may not react well in terms of the voting. Not trying to bully you (or threaten you! :) ), just a heads up. – yshavit Jan 05 '16 at 20:50
  • 3
    Here's a [discussion about this in the bug database](https://bugs.openjdk.java.net/browse/JDK-8125218) – James_D Jan 05 '16 at 20:51
  • Well, since this question originated from a real-world problem, which I have still not solved, I think I'll post about this actual real problem. I suspect the answer will be that it can't be done the way I want it to, but I hope it won't. – Itai Jan 05 '16 at 21:09
  • 1
    I have posted a concrete question: http://stackoverflow.com/questions/34621485/apply-longproperty-to-tablecolumn-programmatically-vs-semantically – Itai Jan 05 '16 at 21:25
  • @sillyfly You should however probably mark this answer as correct, since it does correctly answer the question you asked here. – James_D Jan 06 '16 at 00:30
  • Oops, forgot. Marked now. – Itai Jan 06 '16 at 00:47