为什么Ruby制定者在课堂上需要“自我”的资格?

Ruby setter(无论是由(c)attr_accessor创build的还是手动创build的(c)attr_accessor似乎是唯一需要self.方法self. 在class级本身进行访问时的资格。 这似乎把Ruby独自的语言世界:

  • 所有的方法都需要self / this (像Perl,而我认为是Javascript)
  • 没有方法需要self / this是(C#,Java)
  • 只有setter需要self / this (Ruby?)

最好的比较是C#和Ruby,因为这两种语言都支持访问器方法,这些方法在语法上就像类实例variables一样工作: foo.x = yy = 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(); } } 

问:这是真的吗? 除了制定者之外还有其他需要自我的场合吗? 也就是说,有没有其他的情况下,一个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 } } 

同样的歧义以相同的方式解决。 但是,微妙的,我问的情况下

  • 一个方法已经被定义,并且
  • 没有局部variables被定义,并且

我们遇到

 qwerty = 4 

这是不明确的 – 这是一个方法调用还是一个新的局部variables赋值?


@Mike Stone

嗨! 我理解并欣赏你所提出的观点,你的榜样是伟大的。 当我说的时候相信我,如果我有足够的声望,我会投你的回应。 但我们仍然不同意:

  • 关于语义的问题,和
  • 在事实的中心点

首先我要说的是,不是没有讽刺的是,我们正在对“模棱两可”的含义进行语义辩论。

谈到parsing和编程语言语义(这个问题的主题),你肯定会承认广义的概念“模糊性”。 我们只是采用一些随机的符号:

  1. 模棱两可:词汇模糊(lex必须“向前看”)
  2. 模棱两可:语法模糊(yacc必须推迟到分析树分析)
  3. 有意思的是:在执行的时候知道一切的模糊性

(也有2-3个垃圾)。 所有这些类别都是通过收集更多的上下文信息来解决的,而且在全球范围内越来越多。 所以当你说,

在没有定义variables的情况下,“qwerty = 4”在C#中是UNAMBIGUOUS …

我完全同意。 但是同样的道理,我在说

“qwerty = 4”在ruby中是不含糊的(因为它现在存在)

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

而且我们还没有相互矛盾。 最后,这里是我们真正不同意的地方:要么没有任何进一步的语言结构就可能或不能实现ruby,

对于“qwerty = 4”,ruby无意中调用现有的setter
没有定义局部variables

你说不。 我说是; 另一个ruby可以存在,其行为与当前在所有方面完全一样, 除了 “qwerty = 4”定义了一个新的variables,当没有setter和没有局部存在时,它调用setter(如果存在的话),如果存在则赋值给局部。 我完全同意我可能是错的。 事实上,我可能会错的原因很有趣。

让我解释。

想象一下,你正在编写一个新的面向对象方法的OO语言,看起来像实例variables(比如ruby和C#)。 您可能会从概念性语法开始,如:

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

但是,parsing器编译器(甚至不是运行时)将会呕吐,因为即使在所有的input被修改之后,也无法知道哪个语法是相关的。 你正面临着一个经典的select。 我不能确定的细节,但基本上ruby这样做:

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

这就是为什么它是不明确的,而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可以做同样的事情,但“稍后”必须在运行时,因为作为明确指出,你不知道,直到声明执行哪种情况下适用。

我的问题从来没有打算说“我真的需要'自我'吗?” 或者“避免了什么潜在的歧义?” 相反,我想知道为什么这个特殊的select呢? 也许这不是性能。 也许它只是完成了这项工作,或者认为总是允许一个class轮的当地人来重写一个方法(一个非常罕见的情况要求)是最好的…

但是我有点build议最dynamic的语言可能是推迟这个决定的时间最长的语言,并且select基于最上下文信息的语义:所以如果你没有本地语言并且你定义了一个setter,它会使用setter 。 这不就是为什么我们喜欢ruby,smalltalk,objc,因为方法调用在运行时决定,提供最大的performance力?

这里要记住的重要的事情是Ruby方法可以在任何时候被定义(un),所以为了智能地解决歧义,每个任务都需要运行代码来检查当时是否有一个名字被赋值的方法的任务。

那么,我认为这是这样的原因是因为qwerty = 4是模棱两可的 – 你是定义一个新的variables叫qwerty或调用二传手? Ruby通过说它会创build一个新variables来解决这个模糊问题,因此也就是self. 是必须的。

这是你需要self.另一种情况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以一种明确的方式定义variables。 如果您在C#中定义了一个与访问器名称相同的variables,那么您需要用this.来限定对访问器的调用this. ,就像Ruby的情况一样。

否则,就不可能在方法内部设置局部variables。 variable = some_value是不明确的。 例如:

 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 

如果setter不需要selfsome_method会引发NameError: undefined local variable or method 'some_variable' 。 但是,该方法按预期工作:

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