1. ホーム
  2. ruby

Rubyのセッターは、なぜクラス内で "self. "修飾が必要なのですか?

2023-10-07 15:31:36

質問

Ruby のセッターは (c)attr_accessor を必要とする唯一のメソッドであるように見えます。 self. を必要とする唯一のメソッドです。 これは、Rubyを言語の世界では孤独な存在にしているようです。

  • すべてのメソッドに self / this (Perlのような、そしてJavascriptのような)
  • どのメソッドも self / this は (C#、Java)
  • セッターのみ必要な self / this (ルビー?)

C# と Ruby を比較するのが最も良い方法です。なぜなら、どちらの言語もクラスのインスタンス変数と同じように構文的に機能するアクセサメソッドをサポートしているからです。 foo.x = y , y = foo.x . C#ではこれらをプロパティと呼びます。

以下は簡単な例で、同じプログラムをRubyで作成し、C#で作成したものです。

class A
  def qwerty; @q; end                   # manual getter
  def qwerty=(value); @q = value; end   # manual setter, but attr_accessor is same 
  def asdf; self.qwerty = 4; end        # "self." is necessary in ruby?
  def xxx; asdf; end                    # we can invoke nonsetters w/o "self."
  def dump; puts "qwerty = #{qwerty}"; end
end

a = A.new
a.xxx
a.dump

を取り去り self.qwerty =() を削除すると失敗します(Ruby 1.8.6 on Linux & OS X)。 今度はC#です。

using System;

public class A {
  public A() {}
  int q;
  public int qwerty {
    get { return q; }
    set { q = value; }
  }
  public void asdf() { qwerty = 4; } // C# setters work w/o "this."
  public void xxx()  { asdf(); }     // are just like other methods
  public void dump() { Console.WriteLine("qwerty = {0}", qwerty); }
}

public class Test {
  public static void Main() {
    A a = new A();
    a.xxx();
    a.dump();
  }
}

質問です。これは本当でしょうか? selfが必要な場面はセッター以外にもあるのでしょうか?例えば、Ruby のメソッドで を呼び出すことができます。 がなければ を呼び出すことができますか?

確かにselfがあるケースはたくさんあります。 になる。 が必要な場合がたくさんあります。 これはRubyに限ったことではありませんが、念のため。

using System;

public class A {
  public A() {}
  public int test { get { return 4; }}
  public int useVariable() {
    int test = 5;
    return test;
  }
  public int useMethod() {
    int test = 5;
    return this.test;
  }
}

public class Test {
  public static void Main() {
    A a = new A();
    Console.WriteLine("{0}", a.useVariable()); // prints 5
    Console.WriteLine("{0}", a.useMethod());   // prints 4
  }
}

同じ曖昧さは同じように解決されます。 しかし、微妙なところでは、私が尋ねているのは

  • あるメソッド が定義されており
  • はありません。 ローカル変数が定義されており

に遭遇しました。

qwerty = 4

これはメソッドの呼び出しなのか、それとも新しいローカル変数の代入なのか、どちらなのか曖昧です。


マイク・ストーン

こんにちは!私はあなたの指摘を理解し、感謝しています。 例も素晴らしい。 もし、私に十分な評価があれば、あなたの回答に投票すると思います。 あなたの回答に票を入れたと思います。 しかし、私たちはまだ同意していません。

  • 意味論の問題で、そして
  • 事実の中心的な点に関して

まず、皮肉ではなく、私たちは「曖昧さ」の意味について意味論的な議論をしているのだと主張します。 曖昧さ」の意味について、意味論的な議論をしているのです。

構文解析とプログラミング言語の意味論(この質問の主題)に関して言えば、きっとあなたは幅広い概念を認めるでしょう。 この質問の主題)に関しては、きっとあなたは「曖昧さ」という概念の広範なスペクトルを認めるでしょう。 曖昧さ」という概念の広い範囲を認めるはずです。 ちょっとランダムな表記を採用しましょう。

  1. 曖昧:語彙的な曖昧さ(lexは「先を見通す」必要がある)
  2. 曖昧:文法的な曖昧さ(yaccは構文木解析に委ねなければならない)
  3. AMBIGUOUS: 実行時にすべてを知っている曖昧さ

(そして、2-3の間にもガラクタがあります)。 これらのカテゴリーはすべて、以下の方法で解決されます。 より多くの文脈的な情報を収集し、よりグローバルに見ることによって解決されます。 ですから、あなたが と言うと

<ブロッククオート

C# では "qwerty = 4" は UNAMBIGUOUS である。 という変数が定義されていない場合...

これ以上ないくらい同意です。 しかし、同じ意味で、私が言っているのは

qwerty = 4" は ruby では曖昧さがありません。 (現在存在する)

C# では "qwerty = 4" は曖昧である。

そして、まだお互いに矛盾はしていません。 最後に、ここで私たちは本当に 意見が分かれるところです。ruby は、それ以上何もせずに実装することができたか、できなかったかのどちらかです。 というような言語構成なしで実装することができたかできなかったかです。

qwerty = 4 の場合、ruby は UNAMBIGUOUSLY で次のようになります。 がある場合、既存のセッターを呼び出します。

ローカル変数が定義されていない場合

あなたはノーと言います。 私はイエスと言います。 存在し得るのです。 ただし qwerty = 4" は新しい変数を定義します。 セッターもローカルも存在しない場合、新しい変数を定義し、セッターが存在する場合はそれを呼び出します。 が存在する場合はセッターを呼び出し、存在する場合はローカルに代入します。 私は、私が間違っている可能性があることを完全に受け入れます。 が間違っている可能性は十分にあります。 実際、私が間違っているかもしれない理由は興味深いものです。

説明しましょう。

あなたが新しいOO言語を書いていて、アクセサメソッドがインスタンスのバーのように見えるとします。 (ruby や C# のような) インスタンスバーのようなアクセサメソッドを持つ新しい OO 言語を書くとします。 おそらく、次のような概念的な文法から始めることになるでしょう。 概念的な文法は以下のようなものです。

  var = expr    // assignment
  method = expr // setter method invocation

しかし、パーサ・コンパイラ(ランタイムでさえも)は吐き気をもよおすでしょう。 なぜなら、すべての入力が理解された後でも、どの文法が適切なのかを知る方法がないからです。 古典的な選択を迫られているのだ。 詳しいことはわからないが、基本的にrubyはこうする。 基本的にrubyはこれをやっています。

  var = expr    // assignment (new or existing)
  // method = expr, disallow setter method invocation without .

というのがun-Ambiguousなわけで、whileやC#はこうなっています。

  symbol = expr // push 'symbol=' onto parse tree and decide later
                // if local variable is def'd somewhere in scope: assignment
                // else if a setter is def'd in scope: invocation

C#の場合、「後で」はまだコンパイル時です。

rubyでも同じことができると思いますが、'later'は実行時にしなければならないでしょう。 Ben が指摘するように、ステートメントが実行されるまで、どのケースが適用されるかはわからないからです。 が適用されるか実行されるまでわからないからです。

私の質問は、quot;本当に 'self.' が必要ですか? むしろ私は、なぜこの特定の選択がなされたのかを知りたかったのです。 を知りたいのです。 パフォーマンスではないかもしれない。 もしかしたら、それは、ただ仕事がうまくいっただけかもしれません。 あるいは、常に1ライナーローカルでメソッドをオーバーライドできるようにすることが最善と考えられたのかもしれません。 メソッド (かなり稀なケースの要件) をオーバーライドすることを常に許可することが最善であると考えられたのかもしれません ...

しかし、私は、最も動的な言語は、この決定を最も長く先延ばしにするものであるかもしれないと提案しているようなものです。 この決定を最も長く先延ばしにして、最も文脈的な情報に基づいて意味論を選択する言語が、最も動的な言語であるかもしれないと言いたいのです。 もしローカルがなく、セッターを定義した場合、セッターを使うでしょう。 これは RubyやSmalltalkやObjcが好まれるのは、メソッドの呼び出しが実行時に決定されるからだ。 メソッドの呼び出しが実行時に決定され、最大の表現力を提供するからです。

どのように解決するのか?

ここで覚えておくべき重要なことは、Rubyのメソッドはどの時点でも(未)定義可能であるということです。したがって、曖昧さを知的に解決するには、すべての割り当てで、割り当て時に割り当て先の名前を持つメソッドが存在するかどうかをチェックするコードを実行する必要があるでしょう。