Ruby操作符方法调用vs.普通方法调用

时间:2020-12-19 23:19:30

I'm wondering why calls to operator methods don't require a dot? Or rather, why can't normal methods be called without a dot?

我想知道为什么对运算符方法的调用不需要点?或者更确切地说,为什么没有点就不能调用普通的方法呢?

Example

例子

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 个解决方案

#1


8  

The implementation doesn't have the additional complexity that would be needed to allow generic definition of new operators.

实现不具有允许对新操作符进行通用定义所需的额外复杂性。

Instead, Ruby has a Yacc parser that uses a statically defined grammar. You get the built-in operators and that's it. Symbols occur in a fixed set of sentences in the grammar. As you have noted, the operators can be overloaded, which is more than most languages offer.

相反,Ruby有一个使用静态定义语法的Yacc解析器。你得到了内置的运算符。符号出现在语法的一组固定的句子中。正如您所注意到的,操作符可以重载,这比大多数语言提供的要多。

Certainly it's not because Matz was lazy.

当然,这并不是因为Matz懒惰。

Ruby actually has a fiendishly complex grammar that is roughly at the limit of what can be accomplished in Yacc. To get more complex would require using a less portable compiler generator or it would have required writing the parser by hand in C, and doing that would have limited future implementation portability in its own way as well as not providing the world with the Yacc input. That would be a problem because Ruby's Yacc source code is the only Ruby grammar documentation and is therefore "the standard".

Ruby实际上有一种极其复杂的语法,它几乎是在Yacc中所能完成的极限。要想变得更复杂,就需要使用一个更少的可移植的编译器生成器,或者需要用C语言编写解析器,这样做将会以自己的方式限制未来实现的可移植性,同时也不能为世界提供Yacc输入。这将是一个问题,因为Ruby的Yacc源代码是惟一的Ruby语法文档,因此是“标准”。

#2


12  

The answer to this question, as to pretty much every language design question is: "Just because". Language design is a series of mostly subjective trade-offs. And for most of those subjective trade-offs, the only correct answer to the question why something is the way it is, is simply "because Matz said so".

对于这个问题的答案,几乎所有的语言设计问题都是:“仅仅因为”。语言设计是一系列主要是主观的权衡取舍。对于大多数主观的权衡取舍,唯一正确的答案就是“为什么事情是这样的”,因为“Matz是这么说的”。

There are certainly other choices:

当然还有其他的选择:

  • Lisp doesn't have operators at all. +, -, ::, >, = and so on are simply normal legal function names (variable names, actually), just like foo or bar?

    Lisp根本没有运算符。+、-、:、>、=等都是普通的法律函数名(实际上是变量名),就像foo或bar?

    (plus 1 2)
    (+ 1 2)
    
  • Smalltalk almost doesn't have operators. The only special casing Smalltalk has is that methods which consist only of operator characters do not have to end with a colon. In particular, since there are no operators, all method calls have the same precedence and are evaluated strictly left-to-right: 2 + 3 * 4 is 20, not 14.

    Smalltalk几乎没有运营商。唯一的特殊套管Smalltalk是只有操作符的方法不需要以冒号结束。特别是,由于没有操作符,所有的方法调用都具有相同的优先级,并且严格地从左到右计算:2 + 3 * 4是20,而不是14。

    1 plus: 2
    1 + 2
    
  • Scala almost doesn't have operators. Just like Lisp and Smalltalk, *, -, #::: and so on are simply legal method names. (Actually, they are also legal class, trait, type and field names.) Any method can be called either with or without a dot. If you use the form without the dot and the method takes only a single argument, then you can leave off the brackets as well. Scala does have precedence, though, although it is not user-definable; it is simply determined by the first character of the name. As an added twist, operator method names that end with a colon are inverted or right-associative, i.e. a :: b is equivalent to b.::(a) and not a.::(b).

    Scala几乎没有运算符。就像Lisp和Smalltalk, *, -, #::等等都是合法的方法名。(实际上,它们也是合法的类别、特征、类型和字段名。)任何方法都可以用或不用点来调用。如果您使用没有点的表单,并且该方法只接受一个参数,那么您也可以省略括号。Scala确实有优先权,尽管它不是用户定义的;它只是由名字的第一个字符决定的。作为附加的扭曲,以冒号结尾的运算符方法名是倒立的或右联想的,即a:: b等于b。

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    
  • In Haskell, any function whose name consists of operator symbols is considered an operator. Any function can be treated as an operator by enclosing it in backticks and any operator can be treated as a function by enclosing it in brackets. In addition, the programmer can freely define associativity, fixity and precedence for user-defined operators.

    在Haskell中,任何由运算符符号组成的函数都被认为是运算符。任何函数都可以通过将其封装在回签中来处理为运算符,任何运算符都可以通过将其封装在括号中来处理为函数。此外,程序员可以*地定义用户定义的操作符的结合性、固定性和优先级。

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

There is no particular reason why Ruby couldn't support user-defined operators in a style similar to Scala. There is a reason why Ruby can't support arbitrary methods in operator position, simply because

Ruby不支持与Scala类似的用户定义操作符,这并没有什么特别的原因。Ruby不能在操作符位置支持任意方法是有原因的,原因很简单

foo plus bar

is already legal, and thus this would be a backwards-incompatible change.

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

Another thing to consider is that Ruby wasn't actually fully designed in advance. It was designed through its implementation. Which means that in a lot of places, the implementation is leaking through. For example, there is absolutely no logical reason why

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

puts(!true)

is legal but

是合法的,但

puts(not true)

isn't. The only reason why this is so, is because Matz used an LALR(1) parser to parse a non-LALR(1) language. If he had designed the language first, he would have never picked an LALR(1) parser in the first place, and the expression would be legal.

不是。之所以如此,是因为Matz使用了LALR(1)解析器来解析非LALR(1)语言。如果他首先设计了语言,他就不会首先选择LALR(1)解析器,并且表达式是合法的。

The Refinement feature currently being discussed on ruby-core is another example. The way it is currently specified, will make it impossible to optimize method calls and inline methods, even if the program in question doesn't actually use Refinements at all. With just a simple tweak, it can be just as expressive and powerful, and ensure that the pessimization cost is only incurred for scopes that actually use Refinements. Apparently, the sole reason why it was specified this way, is that a) it was easier to prototype this way, and b) YARV doesn't have an optimizer, so nobody even bothered to think about the implications (well, nobody except Charles Oliver Nutter).

ruby-core上正在讨论的细化特性是另一个例子。当前指定的方式将使优化方法调用和内联方法变得不可能,即使所涉及的程序实际上根本没有使用细化。只需一个简单的调整,它就可以具有同样的表达能力和强大的功能,并确保悲观的代价只发生在实际使用细化的作用域上。显然,这样做的唯一原因是,a)这样做更容易,而且b) YARV没有优化器,所以没有人费心去考虑它的含义(除了Charles Oliver Nutter,没有人知道)。

So, for basically any question you have about Ruby's design, the answer will almost always be either "because Matz said so" or "because in 1993 it was easier to implement that way".

因此,对于关于Ruby设计的任何问题,答案几乎总是要么是“因为Matz这么说”,要么是“因为在1993年以这种方式实现更容易”。

#3


3  

Because Ruby has "syntax sugar" that allows for a variety of convenient syntax for preset situations. For example:

因为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

Here's a list of the operator expressions that may be implemented as methods in Ruby.

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

#4


2  

Because Ruby's syntax was designed to look roughly like popular OO languages, and those use the dot operator to call methods. The language it borrowed its object model from, Smalltalk, didn't use dots for messages, and in fact had a fairly "weird" syntax that many people found off-putting. Ruby has been called "Smalltalk with an Algol syntax," where Algol is the language that gave us the conventions you're talking about here. (Of course, there are actually more differences than just the Algol syntax.)

因为Ruby的语法设计得很像流行的OO语言,它们使用点运算符来调用方法。它从Smalltalk中借用对象模型的语言并没有使用点作为消息,事实上它有一个相当“奇怪”的语法,很多人都觉得这很让人讨厌。Ruby被称为“使用Algol语法的Smalltalk”,在这里,Algol是为我们提供您正在讨论的约定的语言。(当然,这里的差异不仅仅是Algol语法。)

#5


0  

Missing braces was some "advantage" for ruby 1.8, but with ruby 1.9 you can't even write method_0 method_1 some param it will be rejected, so the language goes rather to the strict version instead of freeforms.

对于ruby 1.8来说,缺少大括号是一些“优点”,但是对于ruby 1.9来说,您甚至不能编写method_0 method_0 method_1。

#1


8  

The implementation doesn't have the additional complexity that would be needed to allow generic definition of new operators.

实现不具有允许对新操作符进行通用定义所需的额外复杂性。

Instead, Ruby has a Yacc parser that uses a statically defined grammar. You get the built-in operators and that's it. Symbols occur in a fixed set of sentences in the grammar. As you have noted, the operators can be overloaded, which is more than most languages offer.

相反,Ruby有一个使用静态定义语法的Yacc解析器。你得到了内置的运算符。符号出现在语法的一组固定的句子中。正如您所注意到的,操作符可以重载,这比大多数语言提供的要多。

Certainly it's not because Matz was lazy.

当然,这并不是因为Matz懒惰。

Ruby actually has a fiendishly complex grammar that is roughly at the limit of what can be accomplished in Yacc. To get more complex would require using a less portable compiler generator or it would have required writing the parser by hand in C, and doing that would have limited future implementation portability in its own way as well as not providing the world with the Yacc input. That would be a problem because Ruby's Yacc source code is the only Ruby grammar documentation and is therefore "the standard".

Ruby实际上有一种极其复杂的语法,它几乎是在Yacc中所能完成的极限。要想变得更复杂,就需要使用一个更少的可移植的编译器生成器,或者需要用C语言编写解析器,这样做将会以自己的方式限制未来实现的可移植性,同时也不能为世界提供Yacc输入。这将是一个问题,因为Ruby的Yacc源代码是惟一的Ruby语法文档,因此是“标准”。

#2


12  

The answer to this question, as to pretty much every language design question is: "Just because". Language design is a series of mostly subjective trade-offs. And for most of those subjective trade-offs, the only correct answer to the question why something is the way it is, is simply "because Matz said so".

对于这个问题的答案,几乎所有的语言设计问题都是:“仅仅因为”。语言设计是一系列主要是主观的权衡取舍。对于大多数主观的权衡取舍,唯一正确的答案就是“为什么事情是这样的”,因为“Matz是这么说的”。

There are certainly other choices:

当然还有其他的选择:

  • Lisp doesn't have operators at all. +, -, ::, >, = and so on are simply normal legal function names (variable names, actually), just like foo or bar?

    Lisp根本没有运算符。+、-、:、>、=等都是普通的法律函数名(实际上是变量名),就像foo或bar?

    (plus 1 2)
    (+ 1 2)
    
  • Smalltalk almost doesn't have operators. The only special casing Smalltalk has is that methods which consist only of operator characters do not have to end with a colon. In particular, since there are no operators, all method calls have the same precedence and are evaluated strictly left-to-right: 2 + 3 * 4 is 20, not 14.

    Smalltalk几乎没有运营商。唯一的特殊套管Smalltalk是只有操作符的方法不需要以冒号结束。特别是,由于没有操作符,所有的方法调用都具有相同的优先级,并且严格地从左到右计算:2 + 3 * 4是20,而不是14。

    1 plus: 2
    1 + 2
    
  • Scala almost doesn't have operators. Just like Lisp and Smalltalk, *, -, #::: and so on are simply legal method names. (Actually, they are also legal class, trait, type and field names.) Any method can be called either with or without a dot. If you use the form without the dot and the method takes only a single argument, then you can leave off the brackets as well. Scala does have precedence, though, although it is not user-definable; it is simply determined by the first character of the name. As an added twist, operator method names that end with a colon are inverted or right-associative, i.e. a :: b is equivalent to b.::(a) and not a.::(b).

    Scala几乎没有运算符。就像Lisp和Smalltalk, *, -, #::等等都是合法的方法名。(实际上,它们也是合法的类别、特征、类型和字段名。)任何方法都可以用或不用点来调用。如果您使用没有点的表单,并且该方法只接受一个参数,那么您也可以省略括号。Scala确实有优先权,尽管它不是用户定义的;它只是由名字的第一个字符决定的。作为附加的扭曲,以冒号结尾的运算符方法名是倒立的或右联想的,即a:: b等于b。

    1.plus(2)
    1 plus(2)
    1 plus 2
    1.+(2)
    1 +(2)
    1 + 2
    
  • In Haskell, any function whose name consists of operator symbols is considered an operator. Any function can be treated as an operator by enclosing it in backticks and any operator can be treated as a function by enclosing it in brackets. In addition, the programmer can freely define associativity, fixity and precedence for user-defined operators.

    在Haskell中,任何由运算符符号组成的函数都被认为是运算符。任何函数都可以通过将其封装在回签中来处理为运算符,任何运算符都可以通过将其封装在括号中来处理为函数。此外,程序员可以*地定义用户定义的操作符的结合性、固定性和优先级。

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

There is no particular reason why Ruby couldn't support user-defined operators in a style similar to Scala. There is a reason why Ruby can't support arbitrary methods in operator position, simply because

Ruby不支持与Scala类似的用户定义操作符,这并没有什么特别的原因。Ruby不能在操作符位置支持任意方法是有原因的,原因很简单

foo plus bar

is already legal, and thus this would be a backwards-incompatible change.

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

Another thing to consider is that Ruby wasn't actually fully designed in advance. It was designed through its implementation. Which means that in a lot of places, the implementation is leaking through. For example, there is absolutely no logical reason why

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

puts(!true)

is legal but

是合法的,但

puts(not true)

isn't. The only reason why this is so, is because Matz used an LALR(1) parser to parse a non-LALR(1) language. If he had designed the language first, he would have never picked an LALR(1) parser in the first place, and the expression would be legal.

不是。之所以如此,是因为Matz使用了LALR(1)解析器来解析非LALR(1)语言。如果他首先设计了语言,他就不会首先选择LALR(1)解析器,并且表达式是合法的。

The Refinement feature currently being discussed on ruby-core is another example. The way it is currently specified, will make it impossible to optimize method calls and inline methods, even if the program in question doesn't actually use Refinements at all. With just a simple tweak, it can be just as expressive and powerful, and ensure that the pessimization cost is only incurred for scopes that actually use Refinements. Apparently, the sole reason why it was specified this way, is that a) it was easier to prototype this way, and b) YARV doesn't have an optimizer, so nobody even bothered to think about the implications (well, nobody except Charles Oliver Nutter).

ruby-core上正在讨论的细化特性是另一个例子。当前指定的方式将使优化方法调用和内联方法变得不可能,即使所涉及的程序实际上根本没有使用细化。只需一个简单的调整,它就可以具有同样的表达能力和强大的功能,并确保悲观的代价只发生在实际使用细化的作用域上。显然,这样做的唯一原因是,a)这样做更容易,而且b) YARV没有优化器,所以没有人费心去考虑它的含义(除了Charles Oliver Nutter,没有人知道)。

So, for basically any question you have about Ruby's design, the answer will almost always be either "because Matz said so" or "because in 1993 it was easier to implement that way".

因此,对于关于Ruby设计的任何问题,答案几乎总是要么是“因为Matz这么说”,要么是“因为在1993年以这种方式实现更容易”。

#3


3  

Because Ruby has "syntax sugar" that allows for a variety of convenient syntax for preset situations. For example:

因为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

Here's a list of the operator expressions that may be implemented as methods in Ruby.

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

#4


2  

Because Ruby's syntax was designed to look roughly like popular OO languages, and those use the dot operator to call methods. The language it borrowed its object model from, Smalltalk, didn't use dots for messages, and in fact had a fairly "weird" syntax that many people found off-putting. Ruby has been called "Smalltalk with an Algol syntax," where Algol is the language that gave us the conventions you're talking about here. (Of course, there are actually more differences than just the Algol syntax.)

因为Ruby的语法设计得很像流行的OO语言,它们使用点运算符来调用方法。它从Smalltalk中借用对象模型的语言并没有使用点作为消息,事实上它有一个相当“奇怪”的语法,很多人都觉得这很让人讨厌。Ruby被称为“使用Algol语法的Smalltalk”,在这里,Algol是为我们提供您正在讨论的约定的语言。(当然,这里的差异不仅仅是Algol语法。)

#5


0  

Missing braces was some "advantage" for ruby 1.8, but with ruby 1.9 you can't even write method_0 method_1 some param it will be rejected, so the language goes rather to the strict version instead of freeforms.

对于ruby 1.8来说,缺少大括号是一些“优点”,但是对于ruby 1.9来说,您甚至不能编写method_0 method_0 method_1。