Subclassing EnumSet to add an interface?

E

Eric Smith

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
 
M

Mike Schilling

Eric Smith said:
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

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.)
 
E

Eric Smith

Mike Schilling
You're not specifying a constructor, so one is being created for you, which
looks like

public Foo()
{
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%.
 
R

Richard Reynolds

Eric Smith said:
Mike Schilling

Yes, I had tried doing that explicitly as well.


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%.

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.
 
T

Tom Hawtin

Eric said:
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
 
L

Lasse Reichstein Nielsen

Eric Smith said:
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
 
L

Lew

Richard said:
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?

As Joshua Bloch advised in /Effective Java/, "prefer composition to inheritance."
 
E

Eric Smith

Richard Reynolds said:
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
 
E

Eric Smith

I said:
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%.

Tom said:
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.
 
L

Lew

Eric said:
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.
 
L

Lew

Eric said:
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.

Apples and oranges. Completely misses the point.

The comment was about using the Java classes correctly, not about using
"object-oriented programming" correctly.
 
E

Eric Smith

Lew said:
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.
 
E

Eric Smith

Lew said:
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.
 
E

Eric Smith

Lew said:
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.
 
T

Tom Hawtin

Eric said:
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
 
E

Eric Smith

Tom Hawtin said:
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
 
P

Patricia Shanahan

Eric Smith wrote:
....
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

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
 
T

Tom Hawtin

Eric said:
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
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.

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
 
E

Eric Smith

Tom said:
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?

Tom said:
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.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,578
Members
45,052
Latest member
LucyCarper

Latest Threads

Top