Ruby - Clear all the global variables - ruby

I am using an existing framework for parallel execution. There are so many global variables being used in this. I could see some of the global variables (yes, we should avoid it, but in this case, I don't have an option) are creating issues. global_variables shows the list of all the global variables used. I want to clear them at the end of every execution. Any suggestions, please? ((

TL;DR
You don't want to clear all globals, as Ruby depends on a number of global variables and constants for proper operation. It's okay to clear the ones you've defined, though.
However, you can't actually undefine globals, although you can certainly re-assign their values. Refactoring to namespaced or lexically-scoped variables should be a longer term objective, even if the suggestions below work for you now. There are many options for passing bindings, values, configuration settings, and object references that don't rely on globals, and reducing variable scope is usually the right thing to do in most cases.
That said, here are some suggestions that may help with your situation. I've also noted some edge cases that may or may not apply to your code, but that should be in the back of your mind when dealing with top-level bindings and global namespaces.
You Can't Undefine or Garbage-Collect Globals
By definition, global variables never go out of scope. That also means the variables themselves can never be garbage-collected either.
Additionally, similarly to instance variables but unlike class or local variables, global variables are auto-vivified* as nil when referenced to prevent NameError. Even if you never actually define $foo, $foo == nil #=> true.
*As a subtle distinction, defined? $foo #=> nil while $foo = nil; defined? $foo #=> "global-variable", but I don't think that has any practical bearing on your question.
If your primary goal is just to "unset" the values of your globals, you can do something like:
NILABLE_GLOBALS = %w[$foo $bar $baz]
NILABLE_GLOBALS.map { eval "#{_1} = nil" }
While the variables are all still technically defined, pragmatically they will respond similarly to being undefined, e.g. by being equal to nil.
Reducing Memory Consumed by Globals
This approach may also minimize the memory footprint of the globals by pointing them all to what amounts to a singleton object, e.g. the sole instance of NilClass. This should reduce memory usage if the values previously stored in your globals are garbage collected when nothing references them any longer. There are perhaps several edge cases, like frozen strings stored in the TOPLEVEL_BINDING, where I'm unsure if the values will truly lose all references and thus be garbage collected, but that's more of a memory management issue than a value assignment or object identity issue, and if memory were a primary concern you wouldn't be using globals in the first place.
So long as you aren't relying on defined? returning nil when the values are reset, this seems like your best option short of refactoring your code to use variables that can go out of scope.
Additional Caveats
If you're using a much older version of Ruby that can't garbage-collect Symbols, assign String objects to your globals when you can. You might also disable frozen strings as a default if you find that they aren't being garbage collected even when no longer referenced. You can inspect ObjectSpace after calling the GC module to look for unwanted Symbol and String objects if memory bloats excessively. While these are unlikely to be real problems for you, at least you have a starting point if they are.

At some early point in your program, record the global variables that are provided by the Ruby interpreter itself and store that it in a constant:
OrigGlobalVars = global_variables
I don't think there is a way to undefine global variables, but you can set all the new ones created by your code to nil by doing this:
(global_variables - OrigGlobalVars).each { |g| eval "#{g} = nil" }
This certainly might break some code that uses the global variables, because the code might not be designed to gracefully handle the case where the variable is nil. But you can fix those cases as they come up.

Related

Setting a global value (and keeping it) within the scope of an eval

I've got a large Rails 5 app (Ruby 2.6.x at present) that makes crucial use of Kernel::eval (please don't tell me to try to refactor this out because eval is dangerous - I didn't write the original code, and this is not in the cards for any time soon).
There are a very wide variety of Ruby expressions (coming out of the db) that can be passed to eval, sometimes of great complexity, making extensive use of classes and resources of the app.
(you might want to jump straight down to BIG EDIT below)
What I want is to be able to set a global value ($global) that will be seen within the scope of the eval execution, but that will not "infect" any of the execution context outside of that. I can't try to interpolate this into the string and pass it down though method params and such, because, as I say, the code being eval'ed is complex and stacks can get very deep, and I want the value to potentially be accessed (though never modified) anywhere within.
I understand about Bindings. I have played around with setting local and instance vars in a binding, and passing this to eval, but inevitably these are not seen inside any method calls within the eval, especially if I'm inside a method of some random class (which I always am). Seems like global is the only possibility. But experimentation shows that a global set inside an eval remains in the code that calls the eval:
2.6.3 :002 > $foo
=> nil
2.6.3 :003 > eval("$foo = 12")
=> 12
2.6.3 :004 > $foo
=> 12
Although I might find some hacky way to deal with this situation, I'm sure you can see where I'd really rather not.
The Binding class offers methods to set local and instance vars dynamically within a Binding object, but nothing for globals (apparently). I've thought about something like this:
...
eval code_string, get_binding()
...
def get_binding
$global = :special_value
binding
end
but I'm really worried, with a Rails app that might be servicing lots of requests at the same time, that these settings of $global will step on each other in unpredictable ways. Related clarifying question: Is a global value in a Rails app global to the entire thing, readable and writable within the scope of all the requests whose servicing may be overlapping in time? (I'm running under Passenger, if that means anything)
So this is a fairly simple and straightforward problem when you understand it, although oddly not addressed in anything I can google about it, and I think I've written enough words. Thanks for any help or ideas to try.
BIG EDIT:
Ok, let me try to refocus this in a different way. I'm getting that the scope of a global can never, no-how, be constrained (duh, right?), but how about this strategy (similar to above):
...
eval code_string, get_binding()
...
def get_binding
luaapg = :special_value ## local used as a pseudo-global
binding
end
So, now I've got this Binding that includes the local var luaapg. I've confirmed that. I eval code_string with this Binding. When I am somewhere inside the execution of code_string, where do I find luaapg - how do I access it? If you look at pretty much every tutorial on this stuff on the web, they show you puts eval("luaapg", get_binding) and voila, the assigned value comes out! But this is too simplistic for real life. When I am in the middle of my code_string, in some method scope of some class, luaapg is not there. I had great hope that this would work, even deep down the stack:
TOPLEVEL_BINDING.local_variable_get(:luaapg)
but it doesn't (I learned about TOPLEVEL_BINDING from here - thanks to that author). So this is the new question: what does it mean to say that I have executed (eval'ed) my code_string in the context of that Binding, which contains a local variable, if I have no way to access that variable, other than with the most simpleminded code? (incidentally I played around with instance vars too - same thing). I'm still hoping there's some magic incantation...
I think you've put your finger on it in the name of the type of variable - it's global - common to all the code in the executing program. I'm not sure exactly how Passenger works but I suspect it runs several copies of your program, so it won't be common between the copies.
To get reliable shared information I think you're going to have to use your database or some sort of information cache like memcached. You choose how you save/name it there.

Static global C-like variables in Ruby

Does Ruby has static global variables?
With this I mean global variables only accessible from the file where they were defined.
Short answer: No.
The long answer is more complicated.
There's only one global namespace in Ruby and any alterations to it from any code will have the effect of changing it for all code. To keep things local you need to scope them to a particular context, typically module or class. For example:
module PrivateStuff
#private_variable = "Private (mostly)"
def self.expose_private_variable
#private_variable
end
end
Note this doesn't prevent others from accessing your private variables using instance_variable_get or techniques like that.
This usually isn't a big deal since global variables are usually a sign of bad design and should be avoided unless there's no alternative, a case that's exceedingly rare.
Unlike compiled languages which enforce very strict rules when it comes to data access, Ruby leaves it up to the programmer to be disciplined and simply not do it in the first place.

How to name bools that hold the return value of IsFoo() functions?

I read that it's a good convention to name functions that return a bool like IsChecksumCorrect(Packet), but I also read that it's a good convention to name boolean variables like IsAvailable = True
But the two rules are incompatible: I can't write:
IsChecksumCorrect = IsChecksumCorrect(Packet)
So what's the best way to name vars that store boolean values returned by such functions?
PS: Extra points if you can think of a way that doesn't depend on changing the case (some languages--like Delphi--are case-insensitive).
First of all, there can be difficulties only with functions that don't require arguments, in your example instead the variable should just be called IsPacketChecksumCorrect.
Even with functions with no arguments I think you would only have problems if you were just caching the result of the function, for performance's sake, and you could safely replace all instances of the variables with calls to the function if it weren't for the performance. In all other cases I think that you could always come up with a more specific name for the variable.
If you were indeed just caching, why not just call the variable Functionname_cache? It seems quite clear to me.
If you needed to use a lot this "technique" in your project and _cache seemed too long or you did not like it you could well settle on a convention of your own; as long as you are consistent you can adopt whatever works best for you, people new to the project just need to be explained the convention once and they will easily recognize it ever after.
By the way, there are various opinions on the conventions for the naming of booleans. Personally I prefer to put the subject first, which makes the Ifs more readable, e.g. ChecksumIsCorrect, ChecksumCorrect or ChecksumCorrectness. I actually prefer not to put the Is altogether, the name usually remains clear even if you omit it.

What memory is created/referenced when when an object is passed to a method? [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is Ruby pass by reference or by value?
Working with Ruby, when passing an object to a method, how is the memory of this object handled?
Coming from a C background, I can think of several things which may be happening:
A copy of the memory associated with the according object and is made available to the method being called. In which case the modification of the object would only be reflected in the context of method being called, and not the calling method.
A reference to the memory of the object is passed the method being called (essentially a pointer). Hence any changes made by the object by the method being called or the calling method would be reflected in both contexts. As well, should this program be multithreaded, some kind of mechanism (mutex, semaphore, etc.) must be used to ensure mutually exclusive access to that memory performing write operations.
Something else I am unable to think of... maybe a memory model similar to that of Go... Pipes... MessagePassing...?
What is actually happening?
Ruby uses pass-by-value, or more precisely, a special case of pass-by-value where the value being passed is always a pointer. This special case is also sometimes known as call-by-sharing, call-by-object-sharing or call-by-object.
It's the same convention that is used by more or less every object-oriented language ever created.
Note: on all existing Ruby implementations Symbols, Fixnums and Floats are actually passed directly by value and not with an intermediary pointer. However, since those three are immutable, there is no observable behavioral difference between pass-by-value and call-by-object-sharing in this case, so you can greatly simplify your mental model by simply treating everything as call-by-object-sharing. Just interpret these three special cases as internal compiler optimizations that you don't need to worry about.
Here's a simple example you can run to determine the argument passing convention of Ruby (or any other language, after you translate it):
def is_ruby_pass_by_value?(foo)
foo.replace('More precisely, it is call-by-object-sharing!')
foo = 'No, Ruby is pass-by-reference.'
return nil
end
bar = 'Yes, of course, Ruby *is* pass-by-value!'
is_ruby_pass_by_value?(bar)
p bar
# 'More precisely, it is call-by-object-sharing!'
In short: it's your option 2.
Ruby uses your second option, passes the parameter by reference.

Ruby global variables, legitimate uses

I've never seen global variables used in any Ruby code. I understand that their use is frowned upon across languages but they seem actually useless in Ruby. Can anyone point to properly designed code that uses them?
If I'm right and they're redundant/historical, why do they persist in 1.9?
To be clear, I don't mean variables that Ruby sets up for you like $" and $stdin. I mean uses in one's own code.
The only time I see it in decent code is for a log.
$log = Logger.new('foo.log', 'daily')
A constant would probably do fine, but it somehow feels strange calling methods on a constant.
Environment variables are usually Global variables in Ruby.
So are CLASSPATH in jruby and so on...
Also, you can implement cheap singletons using global variables (although it's not advisable).
So, global variables definitely have a place in Ruby.

Resources