「enumの抽象メソッドはgroovyでサポートされてない?」「Yes. でもそれだけじゃねーんだぜ」 #jggug #q

enumの抽象メソッドはgroovyでサポートされてない? #jggug #q - 山pの楽しいお勉強生活 へのアンサーエントリ的な。

Short Answer

enumの抽象メソッドはgroovyでサポートされてない?

はい。Groovyのenumサポートは微妙です。

Long Answer (or Investigation)

以前、自分もこれにやられてenum&メソッドならスッキリかけるところを微妙に技術的負債ライクな迂回コードを書く羽目になりました。

enum EnumSample {
  A {
     String hello() { "from A" }
  },
  B {
     String hello() { "from B" }
  }
  abstract String hello()
}

assert EnumSample.A.hello() == "from A"

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
/private/tmp/hoge.groovy: 1: Can't have an abstract method in a non-abstract class. The class 'EnumSample' must be declared abstract or the method 'java.lang.String hello()' must be implemented.
 @ line 1, column 1.
   enum EnumSample {
   ^

/private/tmp/hoge.groovy: 8: Can't have an abstract method in a non-abstract class. The class 'EnumSample' must be declared abstract or the method 'java.lang.String hello()' must not be abstract.
 @ line 8, column 3.
     abstract String hello()
     ^

2 errors

そう、abstractメソッドはGroovyのenumではまだ使えないのです。

これ、2011/01ぐらいにJIRAに報告されてるんですけど、なぜかUnresolvedのまま。
自分もVoteしてあってVoted合計12なのですが、まったく動きがありません。
ソース読んでませんが、技術的に難しいのでしょうかね。


じゃあ、abstractを取ってデフォルト実装をいれておけばいいかというと...

enum EnumSample {
  A {
     String hello() { "from A" }
  },
  B {
     String hello() { "from B" }
  }
  String hello() { "DEFAULT" }
}

assert EnumSample.A.hello() == "from A"

これはOK.

なのですが...

enum EnumSample {
  A() {
     String hello() { "from A" }
  },
  B() {
     String hello() { "from B" }
  }

  String hello() { "DEFAULT" }
}

assert EnumSample.A.hello() == "from A"

と、(コンストラクタはとりあえず未定義ですが)コンストラクタ呼出用の括弧を付けると...

Assertion failed:

assert EnumSample.A.hello() == "from A"
                  | |       |
                  A DEFAULT false

なんと、メソッドがオーバライドされません。

なので、コンストラクタで各要素ごとの値を設定しようとしても...

enum EnumSample {
  A(1) {
     String hello() { "from A" }
  },
  B(2) {
     String hello() { "from B" }
  }

  String hello() { "DEFAULT" }

  final int number

  EnumSample(int num) {
      this.number = num
  }
}

assert EnumSample.A.number == 1
assert EnumSample.B.number == 2

assert EnumSample.A.hello() == "from A"

Assertion failed:

assert EnumSample.A.hello() == "from A"
                  | |       |
                  A DEFAULT false

NGなのです。

JIRAチケットはたぶんコレ。http://jira.codehaus.org/browse/GROOVY-5353


このenumが使いづらいのはホントにどうにかして欲しいですね。


というわけで是非Voteしましょう*1

*1:パッチ書いてくれるのが一番ありがたい