Ruby运算符方法调用与常规方法调用

我想知道为什么调用操作符方法不需要点? 或者说,为什么普通的方法不能没有点的调用呢?

class Foo
  def +(object)
    puts "this will work"
  end
  def plus(object)
    puts "this won't"
  end
end 
f = Foo.new
f + "anything" # "this will work"
f plus "anything" # NoMethodError: undefined method `plus' for main:Object


这个实现不需要额外的复杂性来允许通用定义新的操作符。

相反,Ruby有一个Yacc分析器,它使用静态定义的语法。 你得到了内置的运营商,就是这样。 符号出现在语法中一组固定的句子中。 正如你所指出的,运营商可能会超载,这比大多数语言提供的要多。

当然,这不是因为马茨懒惰。

Ruby实际上有一个非常复杂的语法,它大致处于Yacc可以完成的极限。 要想变得更加复杂,需要使用不太便携的编译器生成器,或者需要用C编写解析器,这样做会以自己的方式限制未来的实现可移植性,并且不会为世界提供Yacc输入。 这将是一个问题,因为Ruby的Yacc源代码是唯一的Ruby语法文档,因此是“标准”。


对于这个问题的答案,几乎所有的语言设计问题都是:“仅仅因为”。 语言设计是一系列主要是主观的权衡。 而对于这些主观权衡的大部分来说,对于问题为什么是这样的问题,唯一正确的答案就是“因为马茨这么说”。

当然还有其他选择:

  • Lisp根本没有运营商。 +-::>=等等只是普通的合法函数名称(实际上是变量名称),就像foobar?

    (plus 1 2)
    (+ 1 2)
    
  • Smalltalk几乎没有运营商。 Smalltalk唯一的特殊外壳是只包含操作符的方法不必以冒号结尾。 特别是,由于没有操作符,所有方法调用都具有相同的优先级,并严格按照从左到右的顺序进行评估: 2 + 3 * 420 ,而不是14

    1 plus: 2
    1 + 2
    
  • 斯卡拉几乎没有运营商。 就像Lisp和Smalltalk一样, *-#:::等等只是合法的方法名称。 (实际上,它们也是法律类,特质,类型和字段名称。)任何方法都可以使用或不使用点来调用。 如果您使用没有点的表单,并且该方法只接受一个参数,那么您也可以省略括号。 尽管Scala确实有优先权,但它不是用户可定义的; 它仅由名称的第一个字符决定。 作为一个附加的转折,以冒号结尾的运算符方法名称是倒置的或右联合的,即a :: b等同于b.::(a)而不是a.::(b)

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    
  • 在Haskell中,任何名称由操作符组成的函数都被认为是一个操作符。 任何函数都可以被视为一个操作符,通过将它包含在反引号中,并且任何操作符都可以被视为一个函数,方法是将它括在括号中。 另外,程序员可以为用户定义的操作员自由定义关联性,固定性和优先级。

    plus 1 2
    1 `plus` 2
    (+) 1 2
    1 + 2
    
  • Ruby无法支持类似于Scala的风格的用户定义的运算符没有特别的理由。 有一个原因,为什么Ruby不能在运算符位置支持任意方法,仅仅是因为

    foo plus bar
    

    已经是合法的,因此这将是一个倒退不相容的变化。

    另一件需要考虑的事情是,Ruby实际上并未事先完全设计。 它是通过它的实现而设计的。 这意味着在很多地方,实施正在泄漏。 例如,为什么没有合乎逻辑的理由

    puts(!true)
    

    是合法的,但

    puts(not true)
    

    不是。 这是因为Matz使用LALR(1)解析器来解析非LALR(1)语言的唯一原因。 如果他先设计了语言,那么他从来没有选择过LALR(1)语法分析器,而表达式是合法的。

    目前正在ruby-core上讨论的Refinement功能是另一个例子。 它是目前指定的方式,将使其无法优化方法调用和内联方法,即使有问题的程序实际上并未使用Refinement所有秒。 只需简单的调整,它就可以表达和强大,并确保只有实际使用Refinement的范围才会产生潜在成本。 显然,这样指定的唯一原因是a)以这种方式进行原型设计比较容易,并且b)YARV没有优化器,所以没有人会考虑它的影响(除了查尔斯之外没有人奥利弗Nutter)。

    因此,基本上你对Ruby的设计有任何问题,答案几乎总是或者是“因为Matz这么说”或“因为1993年更容易实现”。


    因为Ruby具有“语法糖”,可以为预设情况提供各种方便的语法。 例如:

    class Foo
      def bar=( o ); end
    end
    
    # This is actually calling the bar= method with a parameter, not assigning a value
    Foo.new.bar = 42
    

    以下是可以在Ruby中作为方法实现的运算符表达式的列表。

    链接地址: http://www.djcxy.com/p/95429.html

    上一篇: Ruby operator method calls vs. normal method calls

    下一篇: ruby how to define writer method with "<<"