祚

rubyがどのように解釈しているかはrubyに聞くのが一番ということで、
次のコードを考えてみました。

~~~
iseq = RubyVM::InstructionSequence.compile(<<END)
p (-1).abs
p = 10
p (-1).abs
END
puts iseq.disasm
~~~

結果は

~~~
== disasm: #<ISeq:<compiled>@<compiled>>================================
local table (size: 2, argc: 0 [opts: 0, rest: -1, post: 0, block: -1,
kw: -1@-1, kwrest: -1])
[ 2] p

# p (-1).abs

0000 trace            1                                               (   1)
0002 putself
0003 putobject        -1
0005 opt_send_without_block <callinfo!mid:abs, argc:0, ARGS_SIMPLE>, <callcache>
0008 opt_send_without_block <callinfo!mid:p, argc:1,
FCALL|ARGS_SIMPLE>, <callcache>
0011 pop

# p = 10
0012 trace            1                                               (   2)
0014 putobject        10
0016 setlocal_OP__WC__0 2

# p (-1).abs
0018 trace            1                                               (   3)
0020 putself
0021 putobject        -1
0023 opt_send_without_block <callinfo!mid:p, argc:1,
FCALL|ARGS_SIMPLE>, <callcache>
0026 opt_send_without_block <callinfo!mid:abs, argc:0, ARGS_SIMPLE>, <callcache>
0029 leave
~~~

putobject -1 の行次にある abs, p (いずれも opt_send_without_block で始まる行)
の順序を見ると、

* 最初の実行では ー1 に abs が適用され、次に p が適用されている
* 2回目の実行では -1 に p が適用され、次に abs が適用されている

となっていますので、これが表示に違いとして出てくるのではないでしょうか。

なお、確かに動作が変わるのですが、私見では

* 同一スコープに同じ名前のメソッドとローカル変数がある
* メソッド(p) の呼び出しで、括弧を省略している

場合の動作なので、文法というレベルではなく実装依存のレベルのように思います。
適用順を明示的に指定するのであれば、括弧をつければ良いだけですし、同一スコープで
同じ名前を使用するのは勧められない記述だと思うので。


市田

2017年9月5日 21:55 Tadashi Saito <tad.a.digger / gmail.com>:
> 斎藤と申します。おもしろい問題ですね。
>
> 個人的にはなんとなく既視感があるのですが、過去のメール・チケットの
> 中からは、自分はうまく見つけられませんでした。
>
> Konishiさんが先に投稿されたことで大方カバーされていると思いますが、
> 自分が調べた点を一つ。
>
>> ちなみに、ruby 2.4.1p111での動作です。
>
>
> 手元で試した限り、同名の変数の有無によって振る舞いが変わるのは、
> 1.8.7〜2.4の全ての系列で同じでした。もっと古いRubyについては、
> まだ試していません。
>
> ruby 1.8.7 (2012-06-29 patchlevel 370) [x86_64-linux]
> ruby 1.9.3p551 (2014-11-13 revision 48407) [x86_64-linux]
> ruby 2.0.0p648 (2015-12-16 revision 53162) [x86_64-linux]
> ruby 2.1.10p492 (2016-04-01 revision 54464) [x86_64-linux]
> ruby 2.2.7p470 (2017-03-28 revision 58194) [x86_64-linux]
> ruby 2.3.4p301 (2017-03-30 revision 58214) [x86_64-linux]
> ruby 2.4.1p111 (2017-03-22 revision 58053) [x86_64-linux]
>
> (ちなみに、pが引数をそのまま返り値として返すようになるのは1.9から
> で、1.8.7までは nil が返ります。そのため、1.8.7の実行では (p(-1.3)).abs
> に 対しては nil.abs が実行され、その結果エラーになりました。)
>
> 以上のように、伝統的な振る舞いである(うっかり変えると悲劇が起きそうな)
> のは分かったのですが、これがバグなのか・そうでないのか、JIS/ISO規格の
> どこに書いてあるのか・未定義なのか・はたまた規格違反な振る舞いのか、
> あたりは、自分には判断が付きませんでした。
>
> もし詳しい方が答えてくだされば、自分としてはうれしいです。
> --
> 斎藤 匡