Groovy の Deque

GroovyにおけるProject Coin相当拡張について - uehaj's blog のように Java より先に Groovy にはその機能が存在することがある。でもそれはたまに問題になる。


LinkedList と ArrayDeque はともに Deque であるがその振る舞いが違う。

Deque linkedList = [1,2,3] as LinkedList
Deque arrayDeque = [1,2,3] as ArrayDeque

assert linkedList.pop() == 3   // List#pop
assert arrayDeque.pop() == 1   // Deque#pop

assert linkedList == [1,2]
assert arrayDeque as List == [2,3]  // == で判定できるのは List, Map, Set, 配列


Groovy には List#pop が存在するため LinkedList#pop は List#pop として振舞ってしまう。
Groovy は Java より先に pop が存在したまたま違う振る舞いで実装されてしまった。
Groovy は末尾から出し入れし、Java は先頭から出し入れする。
おそらく Groovy の pop は Perl の振る舞いを参考にして拡張し、Java の pop は Stack extends Vector の振る舞いに合わせたのではないかと思う。


使用する側の対応としては Deque は双方向キューなのでどちらから出し入れするかを指定して操作するのが確実だ。


実際には空のリストから利用すれば問題ないなと思ったら問題があってバグが上がっていた。
http://jira.codehaus.org/browse/GROOVY-4181

Deque stack = new LinkedList()

stack.push(1)              // List#push
stack.push(2)

assert stack.peek() == 2   // Error: Deque#peek を呼び出すので 1 が返る


確かに Stack として利用してこれは困る。
1年前にあがっていて Fix されていないが難しく考えなければ対応はできる。
要するに Stack として振る舞いが正しければいいので List#peek が存在して末尾から値を返せばいいんじゃないかなと思う。*1


確かに Java とは振る舞いがことなるがそもそも Deque が先頭から出し入れする Stack と決めている Java も少しおかしい気がする。
分けて考えて Stack の実装が 2種類あり ArrayDeque は先頭から出し入れし、LinkedList は末尾から出し入れすると考えればおかしいところはなくなる。


このバグがどう解決されるか分からないけど Groovy には Java を活かしつつ実務的に対応していって欲しいと思う。*2

*1:実装上 last の別名ってことになるが意味は異なる

*2:Groovyではprivateが無視されるというのはバグとみなされている - uehaj's blog とか Fix しないで欲しい