Java Forum / General / May 2007
Subclassing EnumSet to add an interface?
Eric Smith - 12 May 2007 07:41 GMT I'd like to create a subclass of EnumSet to implement the Comparable interface (using my own arbitrary ordering, so that I can use the subclass as a key in a dictionary), but I can't seem to figure out how to do it.
I tried:
import java.util.EnumSet;
public abstract class Foo<E extends Enum<E>> extends EnumSet<E> implements Comparable<Foo> { public int compareTo (Foo o) { return 1; // dummy value for now } }
The compiler says:
Foo.java:3: cannot find symbol symbol : constructor EnumSet() location: class java.util.EnumSet<E> public abstract class Foo<E extends Enum<E>> extends EnumSet<E> ^ 1 error
I don't understand why it thinks there should be an EnumSet() constructor, since I'm subclassing it as an abstract class. Any hints or suggestions?
Thanks! Eric
Mike Schilling - 12 May 2007 08:11 GMT > I'd like to create a subclass of EnumSet to implement the Comparable > interface (using my own arbitrary ordering, so that I can use the [quoted text clipped - 22 lines] > ^ > 1 error You're not specifying a constructor, so one is being created for you, which looks like
public Foo() { super(); }
The compiler is complaining that the constructor "super()" is attempting to call doesn't exist. In fact, since EnumSet has no public constructors, it cannot be subclassed (other than, perhaps, within its package.)
Eric Smith - 12 May 2007 10:58 GMT Mike Schilling
> You're not specifying a constructor, so one is being created for you, which > looks like [quoted text clipped - 3 lines] > super(); > } Yes, I had tried doing that explicitly as well.
> In fact, since EnumSet has no public constructors, it > cannot be subclassed (other than, perhaps, within its package.) Thanks, I was afraid that might be the case but wasn't sure.
Ugh. I'll have to write my own EnumSet class.
I never cease to be amazed at how often the standard Java classes do 95% of what I want, but *cannot* be coerced into letting me implement that last 5%.
Richard Reynolds - 12 May 2007 12:02 GMT > Mike Schilling >> You're not specifying a constructor, so one is being created for you, [quoted text clipped - 18 lines] > classes do 95% of what I want, but *cannot* be coerced into > letting me implement that last 5%. Could you write your own class that implements Comparable and just delegates the EumSet methods to a contained EnumSet class? maybe that's what you meant anyway? Richard.
Lew - 12 May 2007 18:35 GMT >> Mike Schilling >>> You're not specifying a constructor, so one is being created for you, [quoted text clipped - 20 lines] > the EumSet methods to a contained EnumSet class? maybe that's what you meant > anyway? As Joshua Bloch advised in /Effective Java/, "prefer composition to inheritance."
 Signature Lew
Eric Smith - 12 May 2007 20:33 GMT > As Joshua Bloch advised in /Effective Java/, "prefer composition to inheritance." Even when you only want to add one simple method?
Lew - 13 May 2007 17:24 GMT >> As Joshua Bloch advised in /Effective Java/, "prefer composition to inheritance." > > Even when you only want to add one simple method? Perhaps especially then. But the advice is "prefer", not "insist on". Why don't you read the book for his detailed reasoning?
The decision isn't based on whether you're only going "to add one simple method". First off, the complexity of the method is completely immaterial. The decision is based on your object model. Your object model is based on your analysis. If your analysis says "B /is-a/n A", then the modeled B inherits from the modeled A. If it doesn't, then B does not inherit from A. Simple. Number of methods not a factor.
Correctness is not simply a matter of counting. Think carefully about your model.
 Signature Lew
Eric Smith - 14 May 2007 00:15 GMT > If your analysis says "B /is-a/n A", > then the modeled B inherits from the modeled A. If it doesn't, then B > does not inherit from A. Simple. Number of methods not a factor. The analysis did say "B is an A". Specifically, it said "B is an A that also does one extra thing."
> Correctness is not simply a matter of counting. Think carefully about > your model. I have thought carefully about it. Condescenion is not helpful.
Eric Smith - 14 May 2007 00:29 GMT > The decision isn't based on whether you're only going "to add one > simple method". First off, the complexity of the method is completely > immaterial. The decision is based on your object model. Your object > model is based on your analysis. If your analysis says "B /is-a/n A", > then the modeled B inherits from the modeled A. If it doesn't, then B > does not inherit from A. Simple. Number of methods not a factor. If A has a bunch of methods, and you need a B that has those methods plus one more, there is a high probability that "B is an A". Number of methods may not directly be a factor, but it's also not completely irrelevant.
Eric Smith - 12 May 2007 20:33 GMT > Could you write your own class that implements Comparable and just delegates > the EumSet methods to a contained EnumSet class? maybe that's what you meant > anyway? If I'm going to the trouble of implementing it myself, I'm going to implement it in terms of bitmaps stored as ints or longs, to make the compareTo function efficent.
But thanks for the idea! Using delegation like that may well solve other problems I face.
Eric
Tom Hawtin - 12 May 2007 12:22 GMT > Ugh. I'll have to write my own EnumSet class. No. Just use Comparator rather than Comparable.
> I never cease to be amazed at how often the standard Java > classes do 95% of what I want, but *cannot* be coerced into > letting me implement that last 5%. You just have to use it correctly.
Tom Hawtin
Eric Smith - 12 May 2007 20:54 GMT I wrote:
> I never cease to be amazed at how often the standard Java > classes do 95% of what I want, but *cannot* be coerced into > letting me implement that last 5%.
> You just have to use it correctly. I originally learned object-oriented programming in Smalltalk. Perhaps Smalltalk taught me to do things incorrectly, though at the time I didn't seem to have trouble with it.
Lew - 13 May 2007 17:26 GMT > I wrote: >> I never cease to be amazed at how often the standard Java [quoted text clipped - 6 lines] > Perhaps Smalltalk taught me to do things incorrectly, though > at the time I didn't seem to have trouble with it. Apples and oranges. Completely misses the point.
The comment was about using the Java classes correctly, not about using "object-oriented programming" correctly.
 Signature Lew
Eric Smith - 14 May 2007 00:19 GMT > Apples and oranges. Completely misses the point. > > The comment was about using the Java classes correctly, not about > using "object-oriented programming" correctly. So what I've learned from you in this thread is:
1) I should use subclassing only when "A is a B" (as it was in my example) 2) I'm using Java wrong
You haven't explained how to reconcile those two points, given that my complaint was in fact about Java not letting me subclass a provided cass.
Tom Hawtin - 14 May 2007 02:14 GMT > 1) I should use subclassing only when "A is a B" (as it was in my example) Your analysis was poor. Does Foo need to be an EnumSet? Given that an instance of EnumSet does practically nothing that an AbstractSet does, it appears not. Then there is Comparable. Must that be implemented by the same class as that which contains the Set? It seems they can easily be kept separate (and therefore probably should).
> 2) I'm using Java wrong Clearly.
Tom Hawtin
Eric Smith - 15 May 2007 07:42 GMT > Your analysis was poor. Does Foo need to be an EnumSet? Given that an > instance of EnumSet does practically nothing that an AbstractSet does, > it appears not. How did you determine that? The reason I wanted to use an EnumSet was in fact that my requirements involve Foo doing nearly everything an EnumSet does. Specifically, I need to be able to construct various sets from Enum elements, add and remove Enum elements from the set, take the union of two sets (adding one to another), and determine whether a particular Enum is in the set. I don't really care in the least what an AbstractSet does.
So in what sense was my analysis of my requirements for a Foo class "poor"?
It may well be that my plan for *implementing" the Foo class in Java was poor, but that's a separate issue.
> Then there is Comparable. Must that be implemented by > the same class as that which contains the Set? It seems they can > easily be kept separate (and therefore probably should). I originally had in mind to use the Foo in several situations, some of which required a Comparable (and not a separate Comparator). Since then I have found ways to avoid the need for Comparable.
My point was that it seemed unreasonable for Java to deny me the ability to extend an EnumSet to add a small amount of new behavior. I can live with the fact that I can't do it, but no one has offered justification as to why such a limitation was a reasonable design choice. The fact there are other ways to do something isn't a good justification for introducing non-orthonality into a design.
Eric
Patricia Shanahan - 15 May 2007 10:17 GMT ...
> My point was that it seemed unreasonable for Java to deny me the > ability to extend an EnumSet to add a small amount of new behavior. [quoted text clipped - 4 lines] > > Eric I think the real issue is the decision to use public static factory methods in class EnumSet rather than having a public constructor.
The factory approach allows the base class to choose the actual class of the object at run time, based on the parameters. A public constructor leaves the actual class in the hands of the caller, through subclassing.
Looking at its source code, EnumSet does take advantage of having control over the subclass. It uses different implementations depending on whether the Enum has no more than 64 elements. The RegularEnumSet implementation takes advantage of the bits fitting in a single long. JumboEnumSet uses an array of long.
Patricia
Tom Hawtin - 15 May 2007 14:00 GMT >> Your analysis was poor. Does Foo need to be an EnumSet? Given that an >> instance of EnumSet does practically nothing that an AbstractSet does, >> it appears not. > > How did you determine that? I read the API docs.
> The reason I wanted to use an EnumSet was > in fact that my requirements involve Foo doing nearly everything an [quoted text clipped - 3 lines] > particular Enum is in the set. I don't really care in the least what > an AbstractSet does. That's what a Set does, right?
> So in what sense was my analysis of my requirements for a Foo class > "poor"? By claiming to require subclassing of a class that doesn't do anything interesting.
> My point was that it seemed unreasonable for Java to deny me the > ability to extend an EnumSet to add a small amount of new behavior. > I can live with the fact that I can't do it, but no one has offered > justification as to why such a limitation was a reasonable design > choice. The fact there are other ways to do something isn't a > good justification for introducing non-orthonality into a design. Look at the documentation. EnumSet has little behaviour itself (over and above that of AbstractSet). It's not a useful class to subclass.
For my money, I'd have made all the collection implementation classes package private, a bit like the implementations in Collections. Leaving them public 'bloats' the API, inheritance exposes implementation and selection of implementation is much easier with creation methods.
Tom Hawtin
Eric Smith - 17 May 2007 03:42 GMT > Your analysis was poor. Does Foo need to be an EnumSet? Given that an > instance of EnumSet does practically nothing that an AbstractSet does, > it appears not. I wrote:
> How did you determine that?
> I read the API docs. You're confusing analysis of requirements with implementation. I determine what object behavior I required; the API docs were neither necessary nor sufficient to do so.
Whether my requirements can be met by an implmentation using EnumSet is a different matter, and for reasons that have been explained in this thread, they cannot.
Lasse Reichstein Nielsen - 12 May 2007 14:26 GMT > I'd like to create a subclass of EnumSet to implement the Comparable > interface (using my own arbitrary ordering, so that I can use the > subclass as a key in a dictionary), but I can't seem to figure > out how to do it. As others have pointed out, EnumSet cannot be subclassed.
Two approaches spring to mind, if all you need are keys based on sets of enum values:
Make an adapter key object containing the EnumSet:
class MyDictionaryKey<T extends Enum> implements Comparable<MyDictionaryKey<T>> { private final EnumSet<T> enumSet; public MyDictionaryKey(EnumSet<T> enumSet) { this.enumSet = enumSet; } public EnumSet<T> getEnumSet() { return enumSet; } public int compareTo(MyDictionaryKey<T> other) { /// ...your impl } }
and use it for keys in your dictionary.
Or, create a Comparator<EnumSet<MyEnum>> and use a dictionary that allows a comparator for the keys.
/L
 Signature Lasse Reichstein Nielsen - lrn@hotpop.com DHTML Death Colors: <URL:http://www.infimum.dk/HTML/rasterTriangleDOM.html> 'Faith without judgement merely degrades the spirit divine.'
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|