2ch の Ruby スレッドを見てみたら、a++ がなぜないかで盛り上がってました。定期的に出る話題。
ぼくも 1.8 では後置 ++ を使いたい時が結構ありました。例えばこんな感じ。
# ["foo", "bar", "baz"] を [[0, "foo"], [1, "bar"], [2, "baz"]] にする i = 0 ary = ary.map do |v| t = [i, v] i += 1 t end
やっぱりこう書きたい!
i = 0 ary = ary.map {|v| [i++, v] }
悔しくてこう書いてみるものの、すぐ考え直して最初の例に落ち着く。
i = -1 ary = ary.map {|v| [i += 1, v] }
場合によっては以下も書いてたかも。
ary2 = [] ary.each_with_index {|i, v| ary2 << [i, v] } ary = ary2
まあでも、++ って往々にしてトリッキーなコードを産むので、ない方がいいかもしれないですね。ちなみに 1.9 では Enumerator#with_index のおかげで、こういうシチュエーションはかなり減りました。
ary = ary.map.with_index {|v, i| [i, v] }
それはそれとして、a++ を (tmp = a; a = tmp.succ; tmp) の syntax sugar にすればいいというのは (前から言われてると思うけど) 、個人的にはそれなりに説得力を感じます。ちょっと実装してみました。
$ ./ruby -e 'a = 0; p a++; p a++; p a' 0 1 2
以下、フィーリングで書いたパッチ。いかにもバグありそう。前置 ++ は reduce/reduce conflict になったので対応してない。あと -- のためには、まず Fixnum#pred か何かを導入するところからはじめないといけないんだよね。String#pred がうまく定義できないということで、却下されたことがあった気がする。
追記: 1.9 には Integer#pred がすでにありました。ありがとうございます > znz さん
Index: parse.y =================================================================== --- parse.y (revision 19747) +++ parse.y (working copy) @@ -703,6 +703,7 @@ %token tCOLON2 /* :: */ %token tCOLON3 /* :: at EXPR_BEG */ %token <id> tOP_ASGN /* +=, -= etc. */ +%token tINC /* ++ */ %token tASSOC /* => */ %token tLPAREN /* ( */ %token tLPAREN_ARG /* ( */ @@ -1819,6 +1820,34 @@ $$ = dispatch2(assign, $1, dispatch2(rescue_mod, $3, $5)); %*/ } + | var_lhs tINC + { + /*%%%*/ + /* (t = a; a = t.succ; t) */ + ID id = internal_id(), vid = $1->nd_vid; + NODE *tidw, *tidr; + if (dyna_in_block()) { + dyna_var(id); + tidw = NEW_DASGN_CURR(id, 0); + tidr = NEW_DVAR(id); + } + else { + local_var(id); + tidw = NEW_LASGN(id, 0); + tidr = NEW_LVAR(id); + } + $$ = block_append( + node_assign(tidw, gettable(vid)), + block_append( + node_assign( + assignable(vid, 0), + NEW_CALL(tidr, rb_intern("succ"), 0)), + tidr)); + fixpos($$, $1); + /*% + $$ = dispatch3(opassign, $1, '+', $1); + %*/ + } | var_lhs tOP_ASGN arg { /*%%%*/ @@ -6764,6 +6793,10 @@ pushback(c); return '+'; } + if (c == '+') { + lex_state = EXPR_BEG; + return tINC; + } if (c == '=') { set_yylval_id('+'); lex_state = EXPR_BEG;