Why does a method call need to be disambiguated when it can in principle be a constant?

时间:2021-11-12 21:30:48

Method calls can usually omit the receiver and the parentheses for the arguments:

方法调用通常可以省略接收器和参数的括号:

def foo; "foo" end
foo # => "foo"

In the case above, foo is ambiguous between method call and reference to a potential local variable. In the absence of the latter, it is interpreted as a method call.

在上面的例子中,foo在方法调用和对潜在局部变量的引用之间是不明确的。在没有后者的情况下,它被解释为方法调用。

However, when the method name can in principle be a constant name (i.e., when it starts with a capital letter, and consists only of letters), it seems to need disambiguation.

但是,当方法名称原则上可以是常量名称时(即,当它以大写字母开头,并且仅包含字母时),它似乎需要消除歧义。

def Foo; "Foo" end
Foo # => NameError: uninitialized constant Foo
Foo() # => "Foo"
self.Foo # => "Foo"

Why is this the case? Why does a method call need to be explicitly distinguished from a reference to a constant even under the absence of a constant with the same name?

为什么会这样?为什么即使没有具有相同名称的常量,也需要将方法调用与对常量的引用明确区分开来?

3 个解决方案

#1


5  

The set of local variables which is in scope at any given point in the program is defined lexically and can thus be determined statically, even as early as parse time. So, Ruby knows even before runtime which local variables are in scope and can thus distinguish between a message send and a local variable dereference.

在程序中任何给定点的范围内的局部变量集是词法定义的,因此可以静态地确定,甚至早在解析时间。因此,Ruby甚至在运行时之前就知道哪些局部变量在范围内,因此可以区分消息发送和局部变量解除引用。

Constants are looked up first lexically, but then via inheritance, i.e. dynamically. It is not known which constants are in scope before runtime. Therefore, to disambiguate, Ruby always assumes it's a constant, unless obviously it isn't, i.e. it takes arguments or has a receiver or both.

首先通过词法查找常量,然后通过继承,即动态地查找常量。在运行时之前,不知道哪些常量在范围内。因此,为了消除歧义,Ruby总是假设它是一个常量,除非显然不是,即它需要参数或有接收器或两者。

#2


2  

There's no big reason behind the difference. I just wanted foo to be behave like foo(), if there's no local variable foo in the scope. I thought it was useful for creating DSL etc. But I saw no reason to make Foo to behave like Foo().

差异背后没有大的理由。我只是希望foo表现得像foo(),如果范围内没有局部变量foo。我认为它对创建DSL等很有用。但我没有理由让Foo表现得像Foo()。

#3


0  

You ask a great question. As you point out ruby wants to treat it as a constant and therefore do a constant lookup.

你问了一个很好的问题。正如您所指出的,ruby希望将其视为常量,因此可以进行常量查找。

The following snippet however shows the current behavior, and then by modifying const_missing, you seem to get the desired behavior. And to tell you the truth I can't seem to break anything.

但是,以下代码段显示了当前行为,然后通过修改const_missing,您似乎获得了所需的行为。而且说实话我似乎无法破坏任何东西。

My conclusion is that this was as somebody already suggested, just a design decision, but its odd because in general ruby favors convention vs enforcement.

我的结论是,这是有人已经建议的,只是一个设计决定,但它很奇怪,因为一般来说,红宝石赞成惯例与执法。

Or I am missing some case where things do get confusing and the wrong thing happens.

或者我错过了一些事情让事情变得混乱而且错误的事情发生的情况。

<script type="text/ruby">
def puts(s); Element['#output'].html = Element['#output'].html + s.to_s.gsub("\n", "<br/>").gsub(" ", "&nbsp;") + "<br/>"; end

class ImAClass
  def self.to_s
    "I am ImAClass Class"
  end
end

def ImAMethod
  "hello"
end

class DontKnowWhatIAm
  def self.to_s
    "a Class"
  end
end

def DontKnowWhatIAm
  "a method"
end

puts "ImAClass: #{ImAClass}" 

begin 
  puts "ImAMethod: #{ImAMethod}" 
rescue Exception => e
  puts "confusion! #{e.message}"
end

puts "ImAMethod(): #{ImAMethod()}"

puts "DontKnowWhatIAm: #{DontKnowWhatIAm}"

puts "DontKnowWhatIAm(): #{DontKnowWhatIAm()}"

class Module
  alias_method :old_const_missing, :const_missing
  def const_missing(c)
    if self.respond_to? c
      self.send c
    else
      old_const_missing(c)
    end
  end
end

class Foo
  def self.Bar
    "im at the bar"
  end
end

puts "now we can just say: Foo::Bar and it works! #{Foo::Bar}"
 
</script>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>
<div id="output" style="font-family: courier"></div>

#1


5  

The set of local variables which is in scope at any given point in the program is defined lexically and can thus be determined statically, even as early as parse time. So, Ruby knows even before runtime which local variables are in scope and can thus distinguish between a message send and a local variable dereference.

在程序中任何给定点的范围内的局部变量集是词法定义的,因此可以静态地确定,甚至早在解析时间。因此,Ruby甚至在运行时之前就知道哪些局部变量在范围内,因此可以区分消息发送和局部变量解除引用。

Constants are looked up first lexically, but then via inheritance, i.e. dynamically. It is not known which constants are in scope before runtime. Therefore, to disambiguate, Ruby always assumes it's a constant, unless obviously it isn't, i.e. it takes arguments or has a receiver or both.

首先通过词法查找常量,然后通过继承,即动态地查找常量。在运行时之前,不知道哪些常量在范围内。因此,为了消除歧义,Ruby总是假设它是一个常量,除非显然不是,即它需要参数或有接收器或两者。

#2


2  

There's no big reason behind the difference. I just wanted foo to be behave like foo(), if there's no local variable foo in the scope. I thought it was useful for creating DSL etc. But I saw no reason to make Foo to behave like Foo().

差异背后没有大的理由。我只是希望foo表现得像foo(),如果范围内没有局部变量foo。我认为它对创建DSL等很有用。但我没有理由让Foo表现得像Foo()。

#3


0  

You ask a great question. As you point out ruby wants to treat it as a constant and therefore do a constant lookup.

你问了一个很好的问题。正如您所指出的,ruby希望将其视为常量,因此可以进行常量查找。

The following snippet however shows the current behavior, and then by modifying const_missing, you seem to get the desired behavior. And to tell you the truth I can't seem to break anything.

但是,以下代码段显示了当前行为,然后通过修改const_missing,您似乎获得了所需的行为。而且说实话我似乎无法破坏任何东西。

My conclusion is that this was as somebody already suggested, just a design decision, but its odd because in general ruby favors convention vs enforcement.

我的结论是,这是有人已经建议的,只是一个设计决定,但它很奇怪,因为一般来说,红宝石赞成惯例与执法。

Or I am missing some case where things do get confusing and the wrong thing happens.

或者我错过了一些事情让事情变得混乱而且错误的事情发生的情况。

<script type="text/ruby">
def puts(s); Element['#output'].html = Element['#output'].html + s.to_s.gsub("\n", "<br/>").gsub(" ", "&nbsp;") + "<br/>"; end

class ImAClass
  def self.to_s
    "I am ImAClass Class"
  end
end

def ImAMethod
  "hello"
end

class DontKnowWhatIAm
  def self.to_s
    "a Class"
  end
end

def DontKnowWhatIAm
  "a method"
end

puts "ImAClass: #{ImAClass}" 

begin 
  puts "ImAMethod: #{ImAMethod}" 
rescue Exception => e
  puts "confusion! #{e.message}"
end

puts "ImAMethod(): #{ImAMethod()}"

puts "DontKnowWhatIAm: #{DontKnowWhatIAm}"

puts "DontKnowWhatIAm(): #{DontKnowWhatIAm()}"

class Module
  alias_method :old_const_missing, :const_missing
  def const_missing(c)
    if self.respond_to? c
      self.send c
    else
      old_const_missing(c)
    end
  end
end

class Foo
  def self.Bar
    "im at the bar"
  end
end

puts "now we can just say: Foo::Bar and it works! #{Foo::Bar}"
 
</script>


<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://rawgit.com/reactive-ruby/inline-reactive-ruby/master/inline-reactive-ruby.js"></script>
<div id="output" style="font-family: courier"></div>