Static global C-like variables in Ruby - 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.

Related

Ruby - Clear all the global variables

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.

Why is using a class variable in Ruby considered a 'code smell'?

According to Reek, creating a class variable is considered a 'code smell'. What is the explanation behind this?
As you can find in their documentation on Class Variables:
Class variables form part of the global runtime state, and as such make it easy for one part of the system to accidentally or inadvertently depend on another part of the system. So the system becomes more prone to problems where changing something over here breaks something over there. In particular, class variables can make it hard to set up tests (because the context of the test includes all global state).
Essentially, it's a manifestation of global state, which is almost universally considered evil, because it makes tests more difficult and results in a much more fragile class/program structure.
This Stack Overflow question may also be worth reading, which shows the main problem with class variables: if any class inherits from your class and modifies the class variable, every instance of that variable changes, even from the parent! This understandably gives you a way to shoot yourself in the foot easily, so it may be best to avoid them unless you're very careful.
It's also worth comparing class variables with class instance variables. This question has a few good examples which illustrate the usage differences, but in essence class variables are shared, whereas class instance variables are not shared. Therefore, to avoid unwanted side effects, class instance variables are almost always what you want.
In brief, this:
class Shape
##sides = 0
def self.sides
##sides
end
end
class Pentagon < Shape
##sides = 5
end
puts Shape.sides # oops ... prints 5

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.

Ruby: What is considered global, and how do you avoid it?

I am having a tough time grasping the idea of completely avoiding globals in Ruby.
To my understanding, if I define a method, the method would be considered global because I can call the method later on in the script. Same goes for classes. Can you completely avoid globalsl?
Research has pointed my inconclusively towards closures and singleton methods but I am still having trouble understanding how I would 'completely avoid globals.'
EDIT: I have also programmed a bit in JavaScript and used closure as follows to avoid the use of any globals: (function(){...})(); Can something similar be done in Ruby?
It is important to understand the reasoning behind avoiding globals. The main reason is avoiding global state. By storing variable information in a global variable, you are allowing components of the program to behave differently when used in the same way at different times. This usually results in unintended side-effects, causing testing and maintenance issues. Global classes or methods are unable to change (not considering reflection) and are not an issue because of that.
Another thing you may have associated with globals is namespace pollution, which can be partially resolved by nesting namespaces in a way that groups components semantically. Those are still global, though and thus not really avoidable.
Modules and Classes as globals are not a problem.
You could use a module to conceal a class, but ultimately you're going to have some globals.
Avoiding global variables and methods would be advised, though.

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