Vim Advent Calendar 2012 の 362 日目の記事です。
Vim Advent Calendar 2012 も残すところあと4日ですね。寂しいものです。
今回は前回やったキモいシリーズの第2回。
突然だけど、以下の関数はどのような挙動をするだろうか。
function! s:func(time) let time = a:time let suffix = 'min' return 1000-time.suffix endfunction
つまりこういうことか?「time という数値を受け取り、1000からその数値を引き、末尾に 'min' と言うサフィックスを付けた文字列を返す…」
Exactly(そのとおりでございます)
echo s:func(50) " => 950min
では、以下のような値を渡すとどうなるか…
echo s:func({'suffix': 'sec'}) " => 1000
!?
何が起きたのか
return 文の部分を評価される順に () を付けていってみよう。
まずは 50 を渡した場合。
return ((1000-time).suffix)
文字列結合演算子 "." より減算演算子 "-" の方が優先順位が高いため、こうなる。
続いて後者。
return (1000-(time.suffix))
time は辞書になる。減算演算子 "-" より辞書アクセズ演算子 "." の方が優先順位が高いため、こうなる。*1
なんと、評価順序が変わっている!
これは、. 演算子が、左辺の値が文字列か辞書かで意味が変わるため。毎回実行時に動的に変わる。
このような挙動は、静的型付け言語はもちろん、実行時に内部でコンパイルしてASTを生成するような言語でも不可能!*2Vim script すごい。