Program Club

Ruby setter에 "self"가 필요한 이유는 무엇입니까?

proclub 2020. 11. 1. 19:01
반응형

Ruby setter에 "self"가 필요한 이유는 무엇입니까? 학급 내 자격?


Ruby setter는 (c)attr_accessor직접 만들었 든 수동으로 만들었 든 self.클래스 자체 내에서 액세스 할 때 자격 이 필요한 유일한 메서드 인 것처럼 보입니다 . 이것은 Ruby를 언어의 세계에 두는 것 같습니다.

  • 모든 메소드에는 self/ this(Perl과 같은 Javascript)가 필요합니다.
  • self/ thisis (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 =()실패합니다 (Linux 및 OS X의 Ruby 1.8.6). 이제 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 메서드 호출 할 수없는 다른 경우가 있습니까?

자아 필요한 경우는 확실히 많이 있습니다 . 이것은 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 사이의 쓰레기도 있습니다). 이러한 모든 범주는 더 많은 컨텍스트 정보를 수집하고 점점 더 전 세계적으로 살펴봄으로써 해결됩니다. 그래서 당신이 말할 때

"qwerty = 4"는 정의 된 변수가 없을 때 C #에서 UNAMBIGUOUS입니다.

나는 더 이상 동의 할 수 없었다. 하지만 같은 토큰으로

"qwerty = 4"는 루비에서 모호하지 않습니다 (현재 존재 함).

"qwerty = 4"는 C #에서 모호합니다.

그리고 우리는 아직 서로 모순되지 않습니다. 마지막으로, 우리가 정말로 동의하지 않는 부분이 있습니다. 루비는 다음과 같은 추가 언어 구조 없이는 구현 될 수 있거나 구현 될 수 없습니다.

"qwerty = 4"의 경우,
지역 변수가 정의되지 않은 경우 루비 UNAMBIGUOUSLY는 기존 setter를 호출합니다.

You say no. I say yes; another ruby could exist which behaves exactly like the current in every respect, except "qwerty = 4" defines a new variable when no setter and no local exists, it invokes the setter if one exists, and it assigns to the local if one exists. I fully accept that I could be wrong. In fact, a reason why I might be wrong would be interesting.

Let me explain.

Imagine you are writing a new OO language with accessor methods looking like instances vars (like ruby & C#). You'd probably start with conceptual grammars something like:

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

But the parser-compiler (not even the runtime) will puke, because even after all the input is grokked there's no way to know which grammar is pertinent. You're faced which a classic choice. I can't be sure of the details, but basically ruby does this:

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

that is why it's un-Ambiguous, while and C# does this:

  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

For C#, 'later' is still at compile time.

I'm sure ruby could do the same, but 'later' would have to be at runtime, because as ben points out you don't know until the statement is executed which case applies.

My question was never intended to mean "do I really need the 'self.'?" or "what potential ambiguity is being avoided?" Rather I wanted to know why was this particular choice made? Maybe it's not performance. Maybe it just got the job done, or it was considered best to always allow a 1-liner local to override a method (a pretty rare case requirement) ...

But I'm sort of suggesting that the most dynamical language might be the one which postpones this decision the longest, and chooses semantics based on the most contextual info: so if you have no local and you defined a setter, it would use the setter. Isn't this why we like ruby, smalltalk, objc, because method invocation is decided at runtime, offering maximum expressiveness?


The important thing to remember here is that Ruby methods can be (un)defined at any point, so to intelligently resolve the ambiguity, every assignment would need to run code to check whether there is a method with the assigned-to name at the time of assignment.


Well, I think the reason this is the case is because qwerty = 4 is ambiguous—are you defining a new variable called qwerty or calling the setter? Ruby resolves this ambiguity by saying it will create a new variable, thus the self. is required.

Here is another case where you need self.:

class A
  def test
    4
  end
  def use_variable
    test = 5
    test
  end
  def use_method
    test = 5
    self.test
  end
end
a = A.new
a.use_variable # returns 5
a.use_method   # returns 4

As you can see, the access to test is ambiguous, so the self. is required.

Also, this is why the C# example is actually not a good comparison, because you define variables in a way that is unambiguous from using the setter. If you had defined a variable in C# that was the same name as the accessor, you would need to qualify calls to the accessor with this., just like the Ruby case.


Because otherwise it would be impossible to set local variables at all inside of methods. variable = some_value is ambiguous. For example:

class ExampleClass
  attr_reader :last_set
  def method_missing(name, *args)
    if name.to_s =~ /=$/
      @last_set = args.first
    else
      super
    end
  end

  def some_method
    some_variable = 5 # Set a local variable? Or call method_missing?
    puts some_variable
  end
end

If self wasn't required for setters, some_method would raise NameError: undefined local variable or method 'some_variable'. As-is though, the method works as intended:

example = ExampleClass.new
example.blah = 'Some text'
example.last_set #=> "Some text"
example.some_method # prints "5"
example.last_set #=> "Some text"

참고URL : https://stackoverflow.com/questions/44715/why-do-ruby-setters-need-self-qualification-within-the-class

반응형