読者です 読者をやめる 読者になる 読者になる

自インスタンスのインスタンスメソッドを呼び出す時の、selfの使い方がよくわからないんです

ruby
class Sample
  attr_accessor :abc
  def xyz;@xyz;end
  def xyz=(v);@xyz=v;end
  def asdf=(v); p "in asdf with #{v}";end

  def set
    abc = 'def'
    xyz = 'uvw'
    asdf = 'axvaf'
  end
  def print
    p abc
    p xyz
  end

  def set2
    self.abc = 'def2'
    self.xyz = 'uvw2'
    self.asdf = 'qwer'
  end
  def print2
    p self.abc
    p self.xyz
  end
end

o = Sample.new
o.set # => 何も出力されない
p o   # => #<Sample:0x1f72308>

o.set2 # => "in asdf with qwer"
p o    # => #<Sample:0x1f72308 @abc="def2", @xyz="uvw2">

o.print  # => "def2", "uvw2"
o.print2 # => "def2", "uvw2"

なんでや。。なんでself.を書いていないsetではアクセサが呼ばれないんや。。

方々ぐぐっても納得いく説明が見つからない。どの説明でも、このsetの書き方では「メソッド呼び出しではなくローカル変数への代入になるんだよ」と書いてあるだけで、なんでそういう解釈になるのかがよくわからない。

一方でprintの方はself.がなくてもアクセサメソッド呼び出しになっている訳じゃないですか。rubyはそういうものということですかね。。

ぐぐったメモ

第1章 Ruby言語ミニマム

しかし自分自身のメソッドを呼ぶのに「自分の」とわざわざ指定しなければな らないのは面倒だ。それでselfに対する呼び出しのときはメソッドを呼び出す 対象のオブジェクト(レシーバreceiver)を省略できるようになっている。

→でもsetで省略できてないじゃないですか。。

Why does attr_accessor in module require 'self.'? - Ruby Forum

ruby's parser sees "a = ..." and assumes that "a" is local variable, rather than attempting to call #a= (the writer method). This has the advantage that, since local variables always "shadow" methods of the same name, you can write code with the confidence that you are not invoking some method defined in the class (or somewhere up the ancestor chain) that you hadn't noticed. For one thing, this makes it easier to write code that knows as little as possible about its context, and hence can be shared around by Module#include or even copy-n-paste.

→「先にローカル変数と解釈される方が、知らんうちに意図しないメソッドを呼んだことになるよりよくない?」みたいな。インスタンス変数を変えてしまうsetterに限ってはそうかもしれない。buf = 'abc'と何の気なしに書いたら実はmixinしたやつにbufってプロパティがあってそっちが変更されてしまっていた、とかなったりすると目も当てられない。

class Foo
  attr_accessor :x

  def bar
    # If this were the same as self.x = 2, or @x = 2,
    # it would not be possible to have a local variable 'x'?
    x = 2
  end
end

→「x = 2で#x=()を呼び出したことになるんなら、ローカル変数xってどうやっても使えなくならね?」みたいな。メソッド名に=が付くもの限定ルールかな。

違った。思い違いしていた。

attr_accessorで一括定義したアクセサメソッドなんだから、selfを省略してp abcって書けるならabc = 'vvv'って書けなきゃおかしくない?」って思ってた。。

abc = 'def'これはよくある代入式の書き方。

で、obj.a = 1obj.a=(1)のシンタックスシュガーなので、attr_accessor :aなどで定義させたアクセサメソッドa=()を呼び出したかったら、self.a=(1)とかself.a = 1とか書いてやるのがメソッドの呼び出し方として普通。

そこで私みたいな不勉強者が調子に乗ってselfを省略してa = 1と書くと、rubyとしてはselfを省略したメソッド呼び出しなのか代入式なのか見分けが付かなくなってしまう。そしたら代入式と解釈しておいた方が余計な副作用も起きないしいいよね、ってことでしょうかね。

これでいいですかね。。(;^ω^)ほひー

参考: 第8章 Ruby言語の詳細