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

守給你的承諾、 提交于 2019-12-30 04:49:11

问题


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.

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?


回答1:


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.

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.




回答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().




回答3:


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

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.

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>


来源:https://stackoverflow.com/questions/34657494/why-does-a-method-call-need-to-be-disambiguated-when-it-can-in-principle-be-a-co

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!