Ruby操作符方法调用与普通方法调用

mpd*_*mpd 12 ruby methods syntax

我想知道为什么调用operator方法不需要点?或者更确切地说,为什么不能在没有点的情况下调用普通方法?

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

Jör*_*tag 12

对于这个问题的答案,几乎每个语言设计问题都是:"只是因为".语言设计是一系列主要的主观权衡.对于大多数主观权衡,对于为什么事情就是这样的问题,唯一正确的答案就是"因为Matz这么说".

当然还有其他选择:

  • Lisp的没有运营商所有.+,-,::,>,=等仅仅是正常的合法函数名(变量名,实际上),就像foobar?

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

    1 plus: 2
    1 + 2
    
    Run Code Online (Sandbox Code Playgroud)
  • Scala 几乎没有运营商.就像Lisp和Smalltalk的,*,-,#:::等仅仅是合法的方法名.(实际上,它们也是合法的类,特征,类型和字段名称.)任何方法都可以使用或不使用点调用.如果您使用不带点的表单,并且该方法只接受一个参数,那么您也可以不使用括号.尽管Scala 确实具有优先权,但它不是用户可定义的; 它只是由名字的第一个字符决定.作为一个额外的转折,以冒号结尾的运算符方法名称是反转的或右关联的,即a :: b相当于b.::(a)和不相等a.::(b).

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    
    Run Code Online (Sandbox Code Playgroud)
  • 在Haskell中,任何名称由运算符符号组成的函数都被视为运算符.通过将任何函数括在反引号中,可以将任何函数视为运算符,并且可以通过将任何运算符括在括号中来将其视为函数.此外,程序员可以自由地为用户定义的运算符定义关联性,固定性和优先级.

    plus 1 2
    1 `plus` 2
    (+) 1 2
    1 + 2
    
    Run Code Online (Sandbox Code Playgroud)

没有特别的理由说明Ruby不能以类似于Scala的样式支持用户定义的运算符.还有就是为什么红宝石不能支持运营商的地位任意方法,仅仅是因为一个理由

foo plus bar
Run Code Online (Sandbox Code Playgroud)

已经合法的,因此这将是一个向后兼容的变化.

另一件需要考虑的事情是Ruby实际上并没有事先完全设计好.它是通过实施而设计的.这意味着在很多地方,实施都在泄漏.例如,绝对没有逻辑上的原因

puts(!true)
Run Code Online (Sandbox Code Playgroud)

是合法的但是

puts(not true)
Run Code Online (Sandbox Code Playgroud)

不是.唯一的原因,为什么会这样,是因为马茨使用的LALR(1)解析器解析非LALR(1)语言.如果他设计了这种语言,他就不会首先选择一个LALR(1)解析器,而且这个表达式是合法的.

Refinement目前正在讨论的特征ruby-core是另一个例子.它当前指定的方式将使得无法优化方法调用和内联方法,即使所讨论的程序实际上根本不使用Refinements.只需进行简单的调整,它就可以表达和强大,确保只有实际使用 Refinement s的范围才会产生悲观化成本.显然,唯一的原因,为什么它被指定这种方式,是一个),这是比较容易为原型这种方式,和b)YARV不具备的优化,所以没有人甚至懒得去想的影响(当然,没有人查尔斯除外Oliver Nutter).

所以,基本上任何您对Ruby的设计问题,答案几乎总是要么"因为马茨是这么说的"或"因为1993年,它是更容易实现这种方式."

  • 什么是"正常"?它肯定不是"异常".所有Niklaus Wirth的语言都是首先设计的.Algol首先被设计出来.Lisp是第一个设计的.实际上,John McCarthy将其设计为数学证明的方便符号,他甚至认为实现它是不可能的!他甚至*告诉*他的学生,他意识到*可以*实施他错了!APL是作为数学教学的符号而发明的,并且仅在稍后实施.Scheme首先设计.ML被设计*并且首先被证明是正确的.FP首先设计,实际上从未实现过! (5认同)

Dig*_*oss 8

该实现没有允许新运算符的通用定义所需的额外复杂性.

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

当然不是因为Matz很懒.

Ruby实际上有一个非常复杂的语法,大致处于Yacc可以实现的极限.为了获得更多的复杂将需要使用更少的便携式编译器生成或者将需要手写解析器在C,和做的是将有自己的方式有限,未来实施的可移植性以及不能提供世界同Yacc的输入.这将是一个问题,因为Ruby的Yacc源代码是唯一的Ruby语法文档,因此是"标准".