Xeebi

home categories feeds

Javascript の comma operator,そして言語ごとのコンマのちょっとした比較

コンマの扱いは意外なほど言語によって異なって,しかし案外意識されないので,気を付けないとハマる.

Python の場合は例えばだいたい tuple を作ってるつもりでいると良くて,同数の時は unpack してくれる.

3,4
# => (3, 4)
a,b = 3,4
# => a==3, b==4
a,b = 4,5,6
# => ValueError: too many values to unpack (expected 2)
a,b,c = 3,4
# => ValueError: need more than 2 values to unpack
mylist = [0,1,2]
mylist[0,1]
# => TypeError: list indices must be integers, not tuple

ちょっと変わった所では

a = 1
b = a, c = (4,5)
# a == 4, c == 5, b == (4,5)

という感じ.知らない間に馴染んでしまって「なんとなくそういう気分」なことが多かったのだが, 一方 Javascript では…

最初に気付いたのがこの案件.

var a = [0,1,2];
console.log(a[0,1]);  // => 1
console.log(a[1,0]);  // => 0
console.log(a[-2,0,231,1]);  // => 1
console.log(a["there",1]);  // => 1

なんやこの(python に慣れてると)直感に反する挙動.僕としては Error 吐くか undefined かなんか返して欲しかった.

そういえば node

> a = 3,4
4
> a
3 // あれ?

とか

> x,y = 4,3
ReferenceError: a is not defined

とかになったこともあった.

これらの正体は comma operator というもの. 平たく言えば expression たちを並べて返り値は最後の評価値となる,というもの. そして結合順位がけっこう低くて,a = 3,4; は実は

(a = 3), 4

で,返り値は最後の 4, a に入るのは 3 ということになるらしい. x,y = 4,3 のほうは

x, (y=4), 3

ということで,最初に x を評価しようとすると Error が吐かれるという事情らしい. なお var a,b; みたいなときのコンマは expression の中にあるわけじゃないから似て非なるものとかいうことだ.

ついでに ruby では

a = 3,4
# => [3,4]
a,b = 3,4
# => [3,4] , a==3, b==4
a,b,c = 6,2
# => [6,2], a==6, b==2, c==nil
a,b = 9,3,1
# => [9,3,1], a==9, b==3

と,なんかあげぽよな感じ.

Haskell? これでかんべんしてください

Prelude> :i (,)
data (,) a b = (,) a b  -- Defined in `GHC.Tuple'
instance (Bounded a, Bounded b) => Bounded (a, b)
  -- Defined in `GHC.Enum'
instance (Eq a, Eq b) => Eq (a, b) -- Defined in `GHC.Classes'
instance (Ord a, Ord b) => Ord (a, b) -- Defined in `GHC.Classes'
instance (Read a, Read b) => Read (a, b) -- Defined in `GHC.Read'
instance (Show a, Show b) => Show (a, b) -- Defined in `GHC.Show'

まあ,っちゅうわけで案外意識してない所でめっちゃハマった,という話. 個人的には最初に触ったので Python のが一番気持ちいいです.