为什么Ruby setter需要;“自我”;课程内的资格?

为什么Ruby setter需要;“自我”;课程内的资格?,ruby,Ruby,Ruby setter无论是由(c)attr\u accessor创建的,还是手动创建的,似乎都是在类本身中访问时需要self.限定的唯一方法。这似乎让Ruby在语言世界中独占鳌头: 所有方法都需要self/this(比如Perl,我认为是Javascript) 没有方法需要self/这个是(C#,Java) 只有setter需要self/这个(Ruby?) 最好的比较是C与Ruby,因为这两种语言都支持语法上与类实例变量类似的访问器方法:foo.x=y,y=foo.x。C#称之为属性 这里

Ruby setter无论是由
(c)attr\u accessor创建的,还是手动创建的,似乎都是在类本身中访问时需要
self.
限定的唯一方法。这似乎让Ruby在语言世界中独占鳌头:

  • 所有方法都需要
    self
    /
    this
    (比如Perl,我认为是Javascript)
  • 没有方法需要
    self
    /
    这个
    是(C#,Java)
  • 只有setter需要
    self
    /
    这个
    (Ruby?)
最好的比较是C与Ruby,因为这两种语言都支持语法上与类实例变量类似的访问器方法:
foo.x=y
y=foo.x
。C#称之为属性

这里有一个简单的例子;Ruby和C#中的相同程序:

去掉self.qwerty=()
,它就会失败(Linux和OS X上的Ruby 1.8.6)。现在C#:

问:这是真的吗?除了二传,还有其他需要自我的场合吗?也就是说,是否有其他情况下没有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
这是一个方法调用还是一个新的局部变量赋值


@迈克·斯通

嗨!我理解并赞赏你提出的观点和你的建议 榜样是伟大的。相信我,如果我有足够的声誉, 我赞成你的回答。但我们仍然不同意:

  • 在语义问题上,以及
  • 以事实为中心
首先,我要说的是,我们正在就 “歧义”的含义

当涉及到解析和编程语言语义时(主题 关于这个问题),你肯定会承认这个概念的广泛性 “歧义”。让我们采用一些随机符号:

  • 歧义:词汇歧义(lex必须“向前看”)
  • 歧义:语法歧义(yacc必须遵循解析树分析)
  • 模棱两可:模棱两可,在执行时知道一切
  • (2-3之间也有垃圾)。所有这些类别都由 收集更多上下文信息,查看越来越多的全局信息。所以当你 说

    “qwerty=4”在C中是明确的# 当没有定义变量时

    我完全同意。但出于同样的原因,我要说

    “qwerty=4”在ruby中没有歧义 (目前的情况)

    “qwerty=4”在C中是不明确的#

    我们还没有互相矛盾。最后,这里是我们真正需要的地方 不同意:如果没有进一步的改进,ruby可能实现,也可能无法实现 语言的结构是这样的

    对于“qwerty=4”,ruby明确表示 如果存在
    没有定义局部变量

    你说不,我说是;另一个ruby可能存在,其行为与 除“qwerty=4”外,各方面的电流定义了一个新的 变量当不存在setter和local时,如果存在setter,则调用setter 存在,如果存在,则分配给本地。我完全接受我 可能是错的。事实上,我可能错的一个原因很有趣

    让我解释一下

    假设您正在编写一种具有访问器方法的新OO语言 比如实例vars(比如ruby&C#)。你可能会从 概念语法类似于:

      var = expr    // assignment
      method = expr // setter method invocation
    
    但是解析器编译器(甚至不是运行时)会呕吐,因为即使在 所有的输入都是错误的,没有办法知道哪个语法是正确的。 你面临着一个经典的选择。我不能确定细节,但是 ruby基本上做到了这一点:

      var = expr    // assignment (new or existing)
      // method = expr, disallow setter method invocation without .
    
      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#做到了这一点:

      var = expr    // assignment (new or existing)
      // method = expr, disallow setter method invocation without .
    
      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#,'later'仍处于编译时

    我相信ruby也可以这样做,但是“以后”必须在运行时,因为 正如ben指出的,在执行语句之前,您不知道是哪种情况 适用

    我的问题从来不是要问“我真的需要‘自我’?”或“什么?” 我想知道为什么会这样 有什么特别的选择吗?也许这不是表演。也许它刚得到这份工作 完成,或者认为最好始终允许1-liner local覆盖 方法(非常罕见的情况要求)

    但我想说的是,最有活力的语言可能是 延迟此决定的时间最长,并根据最上下文的上下文选择语义 信息:因此,如果您没有本地设置,并且您定义了一个setter,那么它将使用setter。不是吗 这就是为什么我们喜欢ruby、smalltalk和objc,因为方法调用是在运行时决定的,
    提供最大的表达能力?

    嗯,我认为这种情况的原因是因为
    qwerty=4
    不明确。您是定义一个名为
    qwerty
    的新变量还是调用setter?Ruby通过说它将创建一个新变量来解决这个歧义,因此需要
    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
    
    如您所见,对
    test
    的访问不明确,因此需要
    self.


    此外,这也是为什么C#示例实际上不是一个好的比较,因为您定义变量的方式与使用setter的方式不同。如果您在C#中定义了一个与访问器同名的变量,那么您需要用
    这个限定对访问器的调用。
    ,就像Ruby案例一样。

    这里需要记住的重要一点是,Ruby方法可以在任何时候(取消)定义,以便智能地解决歧义,每个赋值
    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
    
    example = ExampleClass.new
    example.blah = 'Some text'
    example.last_set #=> "Some text"
    example.some_method # prints "5"
    example.last_set #=> "Some text"