Interpretation as a local variable overrides method name?

后端 未结 3 1780
北荒
北荒 2020-12-11 07:23

As in this question, when a local variable not defined is used within its own assignment, it is evaluated to nil.

x = x # => nil 


        
相关标签:
3条回答
  • 2020-12-11 07:29

    Short answer is, because Matz defined it so. This behavior is one of the very few things I don't like about Ruby. It even gets better:

    a = b if a
    => nil
    a
    => nil
    

    Variable a gets initialized to nil even though in theory a = b statement should under no circumstances be executed.

    0 讨论(0)
  • 2020-12-11 07:30

    I think in your case it's because it's what's expected :P

    1.9.3-p194 :001 > {}.instance_eval{a=1}
     => 1 
    1.9.3-p194 :002 > {}.instance_eval{a}     
    NameError: undefined local variable or method `a' for {}:Hash
        from (irb):2:in `block in irb_binding'
        from (irb):2:in `instance_eval'
        from (irb):2
        from /Users/rafael/.rvm/rubies/ruby-1.9.3-p194/bin/irb:16:in `<main>'
    

    Instance eval evaluates code at instance level so each hash you are declaring is different. If you want to return keys this works

    1.9.3-p194 :003 > {}.instance_eval{keys = self.keys
    1.9.3-p194 :004?>   keys = keys}
     => [] 
    
    0 讨论(0)
  • 2020-12-11 07:41

    In Ruby, because methods can be called without an explicit receiver and without parentheses, there is a syntactic ambiguity between a local variable reference and a receiverless argumentless method call:

    foo
    

    could either mean "call method foo on self with no arguments" or "dereference local variable foo".

    If there exists a local variable foo in scope, this is always interpreted as a local variable dereference, never as a method call.

    So, what does it mean for a local variable to "be in scope"? This is determined syntactically at parse time, not semantically at runtime. This is very important! Local variables are defined at parse time: if an assignment to a local variable is seen by the parser, the local variable is in scope from that point on. It is, however, only initialized at runtime, there is no compile time evaluation of code going on:

    if false
      foo = 42 # from this point on, the local variable foo is in scope
    end
    
    foo # evaluates to nil, since it is declared but not initialized
    

    Why does it make sense for local variables to "shadow" methods and not the way around? Well, if methods did shadow local variables, there would no longer be a way to dereference those local variables. However, if local variables shadow methods, then there is still a way to call those methods: remember, the ambiguity only exists for receiverless argumentless methods calls, if you add an explicit receiver or an explicit argument list, you can still call the method:

    def bar; 'Hello from method' end; public :bar
    
    bar # => 'Hello from method'
    
    bar = 'You will never see this' if false
    
    bar # => nil
    
    bar = 'Hello from local variable'
    
    bar      # => 'Hello from local variable'
    bar()    # => 'Hello from method'
    self.bar # => 'Hello from method'
    
    0 讨论(0)
提交回复
热议问题