I agree. It is possible that some creative refactoring would solve my problem.. You asked 'Does the parser need to construct the Generator'. No, but in this example I have stipulated that it must use one. But perhaps there is a way to refactor so that I don't need to use one, or that the methods that rely on Generator could be grouped in Generator on within a class that contains a generator. I would have to think about it in terms of a real world example.
Aaron Shawlington wrote:I think it's very likely that you should take your difficulties as a design smell - i.e. rethink your wider design, rather than trying to hack the existing one to make it work.
I am not sure I understand the application of Liskov very well. I once believed that it just meant that I shouldn't be allowed to create a subclass that made the method of a parent class have a more restrictive scope or throw an exception not thrown by the parent class. And that doesn't really apply. I did a quick google on Liskov and found that some people interpret it much more liberally. For some people, overriding any method would be a violation. Whatever the correct interpretation of Liskov is, my problem would still exist if the child class had not overriden any methods of the parent (abstract) class.
It violates the Liskov substitution principle for a start - and that's a very sensible principle 99% of the time.
Campbell Ritchie wrote:Will this work?
Thanks for contributing... I hope <fingers crossed> it was obvious in my posting that I already knew that I couldn't override a field and that I didn't want to have hidden fields either. I was trying to describe the problem and then describe the type of solution that I was hoping to find. The code I provided was a pedagogical example for that purpose, not exemplary code.
Campbell Ritchie wrote:No, you can't You can't override fields;
Don't go hiding fields; that way lies confusion and errors.
I did discuss that solution and the problems associated with it.
You initialise fields with the constructor and you initialise superclass fields with the super(...);
As I said, that is a good solution for problem #1 of 2. If I defined the enum (good suggestion) or the Map in the parent class (or interface) then I could avoid a parallel hierarchy and keep the constants tied to the main parser hierarchy classes.
If there are lots of fields, create an object which encapsulates all their values.
LOL! I am guilty of anthropomorphising my classes. I have sibling classes (both derive directly from the same base class) and cousin classes too. YOu will know I have lost it when I start attributing gender.
And so should whoever told you to call them child classes
Absolutely. They can't do either of them now. But if they had done them at the time they implemented the wrapper classes, then they could have done this. Sadly, until they implemented autoboxing the value of this would not have been apparent.
Rob Spoor wrote:In other words, they couldn't do either.
Oh man that is so true. So very, very true.
Winston Gutkowski wrote:And isn't it interesting that offering something as "simple" as autoboxing...is fraught with so many difficulties?
Campbell Ritchie wrote:Bloch (loc cit) gives an example where the behaviour of < > and == on an Integer object gives unexpected and incorrect results.
Perhaps more syntactic sugar should have been made to address this at the time of release. For example, they could have made it an error to create an instance of [Number] that was null. They could have overloaded == when 2 boxed types were involved. But maybe that was impossible for other reasons I haven't considered.
Rob Spoor wrote:If you compare a primitive with an object, the object is always unboxed. That can lead to some surprising NullPointerExceptions.
but the fact is that I don't know ... and I don't really want to have to know either
I have spent about half of my career doing this. I have learned that it usually has more to do with the skill of the person that wrote the code than your own. Some people write easy to follow code with documentation to help you through the rough parts. Others write spaghetti code that is really hard to figure out. I call this latter group the KIA programmers.
when you see a really large set of code that someone else wrote and you can figure the code in a glimsp.
Yeah, you are right. I was thinking about that on the way home. YOurs is a much better example of what mutability look like. No one would expect my assert to pass.
Campbell Ritchie wrote:No, that is not mutability. This is what mutability would look like:-
I choose my wording very carefully. Your introduction to that design principle was a bit vague. You said "I think we end up going back to the earlier post with the quotes from Bloch's book. Maybe we need a new design principle" That sounded to me as if you might have been attributing those words to Bloch, and also possibly some earlier post. I couldn't find such a quote in his book, but didn't look very hard. . I think your principle is valid, but it doesn't say much outside the context of this discussion. For instance, it doesn't say anything about using (or not using) boxed types at any other time. What I am looking for is a design principle that tells me (and other programmers) how to design new API's.
I don't think anything about that design principle, since I created it.
That said, I have since looked at some more APIs (including the Guava libraries) and it is almost a universal practice to build API's with primitves. Indeed, within the implementation code I saw, most programmers seem to use the following rule.
Use boxed types for all variables EXCEPT where performance requires that you use primitives.
. My first rule looks good on paper, but even I wouldn't advocate it given the overwhelming precedent to the contrary.
use primitives for all variables EXCEPT where they must interact with generic types.
This was exactly the conversation I wanted to read. A bunch of experts talking about the ramifications of using boxed vs primitive types. I feel humbled. Truly.
Campbell Ritchie wrote:I think we end up going back to the earlier post with the quotes from Bloch's book. Maybe we need a new design principle
Always use primitives for arithmetic, not boxed objects.
Campbell Ritchie wrote:Bloch's example took 1.7s with longs and 14s with Longs when I tried it a few seconds ago.
Jesper de Jong wrote:The idea is to remove primitives from the Java programming language, but not from the JVM.
This would suggest that more syntactic sugar is needed. So if ++myInteger works, and I think someone suggested that += and *= also work, then why now allow "==" on Integer to compare the values of the Integer? I realize that means you have just overloaded the == operator, but if you can overload the others, why not this? Well the could possibly a problem where you REALLY wanted to compare if two instances of Integer were really the same instance, but in that rare circumstance it would have been sufficient to cast one or the other to Object before doing the compare. But I haven't thought this through, maybe there is some huge problem with that idea. There would probably be objections if we tried to do it now!
Campbell Ritchie, quoting J. Bloch wrote:... the == operator does not operate on intValue() (for Integers) or similar but looks for reference identity.
Also Bloch says you can't use default values; the default value for an Integer field is null, so any attempt to unbox that will cause a NullPointerException.
Why? Didn't we do the same with String? Specifically I can write
Winston Gutkowski wrote:I just don't like the fact that they've changed a supposedly immutable object into a "mutable" one. And it's done silently.
Perhaps there should indeed be a warning about that, just like the warning you get when comparing String with ==.
but not arithmetic or anything that involves boxing AND unboxing in the same "operation"
How can I improve the code?