16

Are these two (valid) generic bounds:

<T extends Enum<T> & MyInterface>
<T extends Enum<? extends MyInterface>>

the same?


Suppose I have an interface

interface MyInterface {
    void someMethod();
}

And some enums that implement it:

enum MyEnumA implements MyInterface {
    A, B, C;
    public void someMethod() {}
}

enum MyEnumB implements MyInterface {
    X, Y, Z;
    public void someMethod() {}
}

And I want to require that an implementation uses not only a MyInterface but also that it is an enum. The "standard" way is by an intersection bound:

static class MyIntersectionClass<T extends Enum<T> & MyInterface> {
    void use(T t) {}
}

But I've discovered that this also works:

static class MyWildcardClass<T extends Enum<? extends MyInterface>> {
    void use(T t) {}
}

With the above, this compiles:

public static void main(String[] args) throws Exception {
    MyIntersectionClass<MyEnumA> a = new MyIntersectionClass<MyEnumA>();
    a.use(MyEnumA.A);
    MyWildcardClass<MyEnumB> b = new MyWildcardClass<MyEnumB>();
    b.use(MyEnumB.X);
}

And the bound works as and intended and required by above for both cases.

Is there a difference between these two bounds, if so what, and is one "better" than the other?

Bohemian
  • 412,405
  • 93
  • 575
  • 722
  • 1
    If they are truly the sane, I'd prefer the intersection because it doesn't use wildcards, which I personally find "unclean" – Bohemian Jan 02 '13 at 13:27

4 Answers4

4

In this specific case there is no difference because Enums formal type parameter is effectively the self type. This is because one can not inherit from Enum like so:

class MyEnumA extends Enum<MyEnum2> {}
class MyEnumB implements MyInterface {}

So yes, semantically they're the same bound, but only because it's Enum.

Ben Schulz
  • 6,101
  • 1
  • 19
  • 15
  • +1 for answering the constructive part of the question and not wasting time on what the "better" syntax is, given they amount to the same thing. – Paul Bellora Jan 02 '13 at 16:30
3

As others have pointed out, both syntaxes achieve the same bounds - and only because of the special case of enums, where we know the T in Enum<T> must be the immediately extending enum type. So in restricting what T can be resolved to, there's no difference.

There is a difference in the possible usage of instances of T, but it's probably such a nuance that it's irrelevant. Consider that the following statement compiles in MyIntersectionClass.use but not MyWildcardClass.use:

T t2 = t.getDeclaringClass().newInstance();

Only these will compile in the latter:

MyInterface t2 = t.getDeclaringClass().newInstance();
Enum<? extends MyInterface> t3 = t.getDeclaringClass().newInstance();
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
2

Since the second one relies on the special fact that Java enums are implemented as MyEnum extends Enum<MyEnum>, I would prefer the first one, which doesn't rely an such assumptions and states your constraints explicitly.

Marko Topolnik
  • 195,646
  • 29
  • 319
  • 436
1

They'll do the same thing, but I would say T extends Enum<? extends MyInterface> is a bit more standard and thus better, if only because it's more commonly and quickly recognizable. Many people don't even know about the & part of generics.

You could also argue that they read slightly differently. T extends Enum<T> & MyInterface I would read as "an enum which also happens to be a MyInterface." T extends Enum<? extends MyInterface> I would read as "an enum that implements MyInterface." So to that extent, it's a matter of personal preference; I prefer the latter.

yshavit
  • 42,327
  • 7
  • 87
  • 124
  • -1 Sorry, but everything after the first clause is subjective and not constructive. – Paul Bellora Jan 02 '13 at 16:35
  • 2
    @PaulBellora OP's question included the question, `and is one "better" than the other`. That is inherently a subjective question, so it seems unfair to dock people for replying to the question. Your downvotes are of course yours to distribute, but I think your reasoning strains the SO [suggestions for downvotes](http://stackoverflow.com/privileges/vote-down), as it is not clearly or perhaps dangerously incorrect, and I'd argue it's not sloppy or no-effort-expanded either. – yshavit Jan 02 '13 at 16:55
  • This is the first time I've downvoted you and I promise I thought about it. Don't take it personally :) – Paul Bellora Jan 02 '13 at 17:55
  • I'm not, don't worry. :) Nor will the 2 points ruin my new year. Difference of opinion on what SO is for, I guess. – yshavit Jan 02 '13 at 18:17