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

时间:2010-12-05 19:54:14

标签: ruby syntax methods

我想知道为什么调用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

5 个答案:

答案 0 :(得分:12)

对于这个问题的答案,就每个语言设计问题而言:“只是因为”。语言设计是一系列主要的主观权衡。对于大多数主观权衡,唯一正确回答问题的原因是什么,只是“因为Matz这么说”。

当然还有其他选择:

  • Lisp根本没有运营商+-::>=等等只是普通的法律函数名称(实际上是变量名称),就像{{1 }或foo

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

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

    a.::(b)
  • 在Haskell中,名称由运算符符号组成的任何函数都被视为运算符。通过将任何函数封装在反引号中,可以将任何函数视为运算符,并且可以通过将任何运算符括在括号中来将其视为函数。此外,程序员可以自由地为用户定义的运算符定义关联性,固定性和优先级。

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    

没有特别的理由说明Ruby不能以类似于Scala的样式支持用户定义的运算符。 为什么Ruby不能在操作员位置支持任意方法的原因,仅仅因为

plus 1 2
1 `plus` 2
(+) 1 2
1 + 2

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

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

绝对没有逻辑上的原因
foo plus bar

合法,但

puts(!true)

是没有的。唯一的原因为什么这是因为,因为Matz使用LALR(1)解析器来解析非LALR(1)语言。如果他先设计了语言,他就不会在第一时间选择一个LALR(1)解析器,而且表达式是合法的。

目前正在puts(not true) 讨论的Refinement功能是另一个例子。当前指定的方式将使不可能优化方法调用和内联方法,即使相关程序实际上并未实际使用ruby-core 。只需进行简单的调整,它就可以表达和强大,确保只有实际使用 Refinement的范围才会产生悲观化成本。显然,为什么以这种方式指定的唯一原因是a)以这种方式原型更容易,并且b)YARV不拥有优化器,所以没有人甚至不屑于考虑其影响(好吧,除了Charles Oliver Nutter之外没有人)。

因此,对于基本任何问题,你有关于Ruby的设计,答案几乎总是“因为Matz这样说”或“因为在1993年它更容易实现这种方式”。 / p>

答案 1 :(得分:8)

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

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

当然不是因为Matz很懒。

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

答案 2 :(得分:3)

因为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中的方法实现的operator expressions列表。

答案 3 :(得分:2)

因为Ruby的语法设计看起来大致像流行的OO语言,并且那些使用点运算符来调用方法。它从Smalltalk借用其对象模型的语言并没有使用点作为消息,事实上它有一种相当“怪异”的语法,许多人发现这种语法很不合适。 Ruby被称为“具有Algol语法的Smalltalk”,其中Algol是一种语言,它为我们提供了您在此处讨论的约定。 (当然,实际上存在的差异不仅仅是Algol语法。)

答案 4 :(得分:0)

缺少大括号对于ruby 1.8来说是一个“优势”,但是对于ruby 1.9,你甚至不能写method_0 method_1 some param它会被拒绝,所以语言更倾向于严格版本而不是自由形式。