From: tsela.cg@... Date: 2007-04-05T20:35:04+09:00 Subject: Re: Avoiding scope pitfall On Apr 5, 12:37 pm, "gga" wrote: > Here's a simple snippet of code of a ruby scope pitfall (bug?) that I > keep stumbling upon. > Here a "global" function is invoked in two different contexts and > returns different behavior due to self being set differently. > > --- > #!/usr/bin/env ruby > > @x = 'hello global' > > def global_func > puts "global_func: class:#{self.class} x=#@x" > end > > class A > def test_scope > global_func > end > end > > global_func > > a = A.new > a.test_scope I don't know why you call that a pitfall. I tested the behaviour and it did exactly what I expected. I think you are confused by what you call "global functions". You'd better forget them: Ruby doesn't have global functions. It only has methods. When you define a so-called "global function", you're just defining a method at the top level, which is in an object of class Oject, called main. Due to the scope rules at the top level, defining a method there adds it to the class Object, as an instance method. Nothing strange there so far. Now when you define class A, it becomes automatically a subclass of Object, as you probably know, since Object is the root of the class hierarchy. As a subclass of Object, it gains all Object's instance methods, including the one you just defined: "global_func" (you can check that by running a.methods). So when you call "global_func" in the test_scope method, you are actually calling an inherited method, which will run then in the scope of the a object you created, *as one would expect from inherited methods*! So when you run a.test_scope, global_func will run in the scope of a, where self.class is A and @x hasn't been assigned and thus returns nil. This is perfectly normal, given the rules of the Ruby language. > --- > > I'm wondering if this is intended behavior in the language. If > intended, what's the best approach to avoid running into this? I'm > currently porting code from other languages with different (more > correct to me) scoping, and this keeps tripping me. Well, the answer is that yes, it is the intended behaviour in the language, in the sense that it is completely valid behaviour according to the rules of the language. Just forget about global functions: they are just methods of the class Object, which become available to all objects only due to inheritance, and thus follow *all* the rules of inherited methods, included the rule that when called in an instance of a subclass, they run in the scope of that instance. Normally functions defined on the top level don't care about this, as their behaviour normally does not depend on the state of the object they're called in (like "puts", which will output to $stdout anyway, since $stdout is a true global variable which refers to the same IO object everywhere). For others, we just don't expect them to behave differently (no one would expect the "class" method to return anything but the class of the object they're in). A way to remember that behaviour might be to remember that methods defined on the top level act as if they had a "class Object ... end" surrounding their definition. That might help you remember that they are inherited to other classes, rather than simply have a global scope. And if you don't want that behaviour, just have your top-level methods never rely on the scope they're running in. That can be done for instance by only have them use global variables (but watch your thread safety go bye-bye if you write threaded code :) ) and local variables (which are local to the scope of the method anyway, wherever that method's used). Hopefully with this you should understand why this behaviour is actually *correct*, when you think clearly about how the Ruby language works (i.e. it's internally consistent). One thing I've noticed and liked about Ruby is how consistent it is, and how few exceptions and little rules you need to learn when you understand its basic principles. You just need to be consistent yourself in how you are applying those basic principles to your programs. Cheers, Christophe.