Why do Global Variables exist in Ruby? [closed] - ruby

Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 5 years ago.
Improve this question
I've read C2Wiki on Global Variables, and I have three questions about them (at the bottom of this post). The main question is: If Global Variables are so bad, why does Ruby have them?
Also, I've noticed some interesting behaviour regarding Global Variables in Ruby, that causes them to work differently to regular global-level constants.
1. Referencing an undefined Global Variable returns nil. Referencing an undefined global constant returns a NameError:
2.2.3 :001 > $THING
=> nil
2.2.3 :002 > THING
NameError: uninitialized constant THING
from (irb):2
from /Users/makerslaptop82/.rvm/rubies/ruby-2.2.3/bin/irb:15:in `<main>'
2. irb is initialized with both $stdout and STDOUT defined. You can redefine $stdout, and this doesn't affect STDOUT:
2.2.3 :001 > $stdout
=> #<IO:<STDOUT>>
2.2.3 :002 > STDOUT
=> #<IO:<STDOUT>>
2.2.3 :003 > $stdout = IO.new(6)
=> #<IO:fd 6>
2.2.3 :004 > $stdout
=> #<IO:fd 6>
2.2.3 :005 > STDOUT
=> #<IO:<STDOUT>>
My questions are:
If Global Variables are so bad, why does Ruby have them?
Why does referencing undefined Global Variables return nil instead of a NameError? Was this choice deliberate? Why?
Is there some danger to having two virtually-identically-named versions of STDOUT in a single program? (I assume there are other globally-defined objects that this applies to as well)

Global variables are not bad. They're not evil. They're just incredibly, incredibly powerful. Which is why you shouldn't use them.
Global variables are global- they can be accessed and modified anywhere in the code. A single global variable has the potential to affect all of your classes, all of your functions, all of the classes and functions of every single library or dependency you load into your project, and all of the classes and functions of every single project which loads your project as a dependency, as well as the projects that load those projects, and so and and so forth, for ever and always, for the rest of time.
The second people start feeling comfortable using global variables, the namespace gets insanely cluttered and we get conflicts left and right and the stability of the programming language itself is threatened. Which is why the use of global variables is emphatically and repeatedly discouraged.
But global variables are not bad. They're like the highway lanes labeled "for emergency vehicles only," or like those fire-axes behind glass labeled "break glass in case of emergency."
It's entirely possible that at some point, in the distant future, you will have an incredibly unusual situation which merits the use of a single global variable. But that day is not today. And it is probably not tomorrow, or a month from now, or a year from now. Daily life, daily code- it just doesn't call for the unbridled power of a global variable.
$stdout is a great example of why global variables are sometimes important. $stdout is the default stream in ruby- the one where things will print if no other stream is specified. $stdout should be accessible from every class and every function in every library because it acts like a giant funnel, shoveling all output to a single location. The whole world knows and agrees that $stdout exists in ruby, and its uses are well-documented, so its power is well-managed.
This isn't to be confused with STDOUT which is a constant representing the actual pipe which sets up a stream between ruby and its parent program (usually a terminal). $stdout = STDOUT by default, but $stdout can be changed to anything. If you want your program to print to a file, you can change $stdout to a file stream.
I don't think this name choice is confusing for a seasoned rubyist. A variable is designed to be modified and a constant is designed to be constant. The difference between $stdout and STDOUT is that the former can be modified to change the standard output location of your program, and the latter is a constant, always pointing to the stdout stream. The capitalization makes a world of difference and conveys very different meanings.
As for why global constants are uninitialized and global variables are nil, that actually has nothing to do with globals. Ruby automatically initializes all variables as nil. You can easily see this with instance variables such as #foo or ##foo. In almost every situation, an undefined local variable will throw a NameError because ruby cannot tell whether it is a variable or a method. But in strange situations, they too are initialized as nil:
puts foo # => NameError: undefined local variable or method 'foo'
foo = 42 if false
puts foo # => nil
puts bar # => NameError
bar = bar
puts bar # => nil
It was a conscious design choice in Ruby not to automatically initialize constants. Because a constant is, by definition, something which is initialized once and then never changed, it would break the definition for a constant to be nil at first and then a different value later in the code.
I should also mention that global constants are considered acceptable, even among people who tout global variables as bad. The difference is that constants can only be assigned once and generally throw a warning or error if they get assigned again. This protects programmers from situations where conflicting global constants might cause problems.

Related

Why can't I overwrite self in the Integer class?

I want to be able to write number.incr, like so:
num = 1; num.incr; num
#=> 2
The error I'm seeing states:
Can't change the value of self
If that's true, how do bang! methods work?
You cannot change the value of self
An object is a class pointer and a set of instance methods (note that this link is an old version of Ruby, because its dramatically simpler, and thus better for explanatory purposes).
"Pointing" at an object means you have a variable which stores the object's location in memory. Then to do anything with the object, you first go to the location in memory (we might say "follow the pointer") to get the object, and then do the thing (e.g. invoke a method, set an ivar).
All Ruby code everywhere is executing in the context of some object. This is where your instance variables get saved, it's where Ruby looks for methods that don't have a receiver (e.g. $stdout is the receiver in $stdout.puts "hi", and the current object is the receiver in puts "hi"). Sometimes you need to do something with the current object. The way to work with objects is through variables, but what variable points at the current object? There isn't one. To fill this need, the keyword self is provided.
self acts like a variable in that it points at the location of the current object. But it is not like a variable, because you can't assign it new value. If you could, the code after that point would suddenly be operating on a different object, which is confusing and has no benefits over just using a variable.
Also remember that the object is tracked by variables which store memory addresses. What is self = 2 supposed to mean? Does it only mean that the current code operates as if it were invoked 2? Or does it mean that all variables pointing at the old object now have their values updated to point at the new one? It isn't really clear, but the former unnecessarily introduces an identity crisis, and the latter is prohibitively expensive and introduce situations where it's unclear what is correct (I'll go into that a bit more below).
You cannot mutate Fixnums
Some objects are special at the C level in Ruby (false, true, nil, fixnums, and symbols).
Variables pointing at them don't actually store a memory location. Instead, the address itself stores the type and identity of the object. Wherever it matters, Ruby checks to see if it's a special object (e.g. when looking up an instance variable), and then extracts the value from it.
So there isn't a spot in memory where the object 123 is stored. Which means self contains the idea of Fixnum 123 rather than a memory address like usual. As with variables, it will get checked for and handled specially when necessary.
Because of this, you cannot mutate the object itself (though it appears they keep a special global variable to allow you to set instance variables on things like Symbols).
Why are they doing all of this? To improve performance, I assume. A number stored in a register is just a series of bits (typically 32 or 64), which means there are hardware instructions for things like addition and multiplication. That is to say the ALU, is wired to perform these operations in a single clock cycle, rather than writing the algorithms with software, which would take many orders of magnitude longer. By storing them like this, they avoid the cost of storing and looking the object in memory, and they gain the advantage that they can directly add the two pointers using hardware. Note, however, that there are still some additional costs in Ruby, that you don't have in C (e.g. checking for overflow and converting result to Bignum).
Bang methods
You can put a bang at the end of any method. It doesn't require the object to change, it's just that people usually try to warn you when you're doing something that could have unexpected side-effects.
class C
def initialize(val)
#val = val # => 12
end # => :initialize
def bang_method!
"My val is: #{#val}" # => "My val is: 12"
end # => :bang_method!
end # => :bang_method!
c = C.new 12 # => #<C:0x007fdac48a7428 #val=12>
c.bang_method! # => "My val is: 12"
c # => #<C:0x007fdac48a7428 #val=12>
Also, there are no bang methods on integers, It wouldn't fit with the paradigm
Fixnum.instance_methods.grep(/!$/) # => [:!]
# Okay, there's one, but it's actually a boolean negation
1.! # => false
# And it's not a Fixnum method, it's an inherited boolean operator
1.method(:!).owner # => BasicObject
# In really, you call it this way, the interpreter translates it
!1 # => false
Alternatives
Make a wrapper object: I'm not going to advocate this one, but it's the closest to what you're trying to do. Basically create your own class, which is mutable, and then make it look like an integer. There's a great blog post walking through this at http://blog.rubybestpractices.com/posts/rklemme/019-Complete_Numeric_Class.html it will get you 95% of the way there
Don't depend directly on the value of a Fixnum: I can't give better advice than this without knowing what you're trying to do / why you feel this is a need.
Also, you should show your code when you ask questions like this. I misunderstood how you were approaching it for a long time.
It's simply impossible to change self to another object. self is the receiver of the message send. There can be only one.
If that's true, how do bang! methods work?
The bang (!) is simply part of the method name. It has absolutely no special meaning whatsoever. It is a convention among Ruby programmers to name surprising variants of less surprising methods with a bang, but that's just that: a convention.

Ruby: Setting a global variable by name

I am trying to dynamically set (not create, it already has to exist) a global ruby variable in a method. The variable name is determined from the passed symbol. What I am currently doing is the following:
def baz(symbol)
eval("$#{symbol}_bar = 42")
end
$foo_bar = 0
baz(:foo)
puts $foo_bar # => 42
But to me, this kind of feels very wrong. Is this the way to do this? Or can it be done differently? Also, I don't know how evals perform in ruby. Does it run much slower than
$foo_bar = 42
The method looks fine to me. This guy says that eval efficiency is much worse, though the post is 3 years old.
I will point out that this method suggests you have a lot of global variables, which is generally a code smell if the code base is significant.
If you can use an instance variable instead, there is Object#instance_variable_set.
def baz(symbol)
instance_variable_set("##{symbol}_bar", 42)
end
Note that it only accepts variable names that can be accepted as an instance variable (starting with #). If you put anything else in the first argument, it will return an error. For the global variable counterpart to it, there is a discussion here: Forum: Ruby
Either way, you also have the problem of accessing the variable. How are you going to do that?

Throw exception when re-assigning a constant in Ruby?

I've long been aware that "constants" in Ruby (i.e., variable names that are capitalized) aren't really constant. Like other programming languages, a reference to an object is the only thing stored in the variable/constant. (Sidebar: Ruby does have the facility to "freeze" referenced objects from being modified, which as far as I know, isn't an ability offered in many other languages.)
So here's my question: when you re-assign a value into a constant, you get a warning like so:
>> FOO = 'bar'
=> "bar"
>> FOO = 'baz'
(irb):2: warning: already initialized constant FOO
=> "baz"
Is there a way to force Ruby to throw an exception instead of printing a warning? It's tough to figure out why reassignments happen sometimes.
Look at Can you ask ruby to treat warnings as errors? to see how it is possible in some cases to treat warnings as errors.
Otherwise I guess you'd have to write a custom method to assign constants and raise the exception if already assigned.
If you know that a reassignment happens to a specific constant, you can also add a sanity check just before the assignment.
You can't intercept it directly, no.
If you really need to do this, I can think of a very dirty hack, though. You could redirect the standard error IO to a custom IO object. The write method could then check for what is being written; if it contains "warning: already initialized constant", then you raise, otherwise you forward the call to the standard error's write.
If the constant is within a class or a module, then you could freeze the class or module:
# Normal scenario
$VERBOSE = true
class Foo
BAR = 1
end
Foo::BAR = 2 # warning: already initialized constant BAR
# Using freeze
Foo.freeze
Foo::BAR = 3
RuntimeError: can't modify frozen Class
from (irb):8
from /Users/agrimm/.rbenv/versions/1.9.3-p194/bin/irb:12:in `<main>'
For your scenario, you could freeze Object, but that sounds kind of scary.

Constant Assignment Bug in Ruby?

We caught some code in Ruby that seems odd, and I was wondering if someone could explain it:
$ irb
irb(main):001:0> APPLE = 'aaa'
=> "aaa"
irb(main):002:0> banana = APPLE
=> "aaa"
irb(main):003:0> banana << 'bbb'
=> "aaabbb"
irb(main):004:0> banana
=> "aaabbb"
irb(main):005:0> APPLE
=> "aaabbb"
Catch that? The constant was appended to at the same time the local variable was.
Known behavior? Expected?
Known behaviour. Constants don't mean that you can't modify the object it refers to, merely that it'll give you a warning (and only a warning) if you assign it to a different object.
In short, ruby constants aren't.
Note: This behaviour is listed in an answer to "What are the Ruby Gotchas a newbie should be warned about?" It's a worthwhile read.
Catch that? The constant was appended to at the same time the local variable was.
No, it wasn't appended to, and neither was the local variable.
The single object that both the constant and the local variable are referring to was appended to, but neither the constant nor the local variable was changed. You cannot modify or change a variable or constant in Ruby (at least not in the way that your question implies), the only thing you can change is objects.
The only two things you can do with variables or constants is dereferencing them and assigning to them.
The constant is a red herring here, it is completely irrelevant to the example given. The only thing that is relevant is that there is only one single object in the entire example. That single object is accessible under two different names. If the object changes, then the object changes. Period. It does not mysteriously split itself in two. Which name you use to look at the changed object doesn't matter. There is only one object anyway.
This works exactly the same as in any other programming language: if you have multiple references to a mutable object in, say, Python, Java, C#, C++, C, Lisp, Smalltalk, JavaScript, PHP, Perl or whatever, then any change to that object will be visible no matter what reference is used, even if some of those references are final or const or whatever that particular language calls it.
This is simply how shared mutable state works and is just one of the many reasons why shared mutable state is bad.
In Ruby, you can generally call the freeze method on any object to make it immutable. However, again, you are modifying the object here, so anybody else who has a reference to that object will all the sudden find that the object has become immutable. Therefore, just to be safe, you need to copy the object first, by calling dup. But of course, that's not enough either, if you think of an array, for example: if you dup the array, you get a different array, but the objects inside the array are the still the same ones in the original array. And if you freeze the array, then you can no longer modify the array, but the objects in the array may very well still be mutable:
ORIG = ['Hello']
CLONE = ORIG.dup.freeze
CLONE[0] << ', World!'
CLONE # => ['Hello, World!']
That's shared mutable state for you. The only way to escape this madness is either to give up shared state (e.g. Actor Programming: if nobody else can see it, then it doesn't matter how often or when it changes) or mutable state (i.e. Functional Programming: if it never changes, then it doesn't matter how many others see it).
The fact that one of the two variables in the original example is actually a constant is completely irrelevant to the problem. There two main differences between a variable and a constant in Ruby: they have different lookup rules, and constants generate a warning if they are assigned to more than once. But in this example, the lookup rules are irrelevant and the constant is assigned to only once, so there really is no difference between a variable and a constant in this case.
You can freeze constants if you want them to be unchangable:
>> APPLE = 'aaa'
=> "aaa"
>> banana = APPLE
=> "aaa"
>> APPLE.freeze
=> "aaa"
>> banana.frozen?
=> true
>> banana << 'bbb'
TypeError: can't modify frozen string
from (irb):5:in `<<'
from (irb):5
Constants in Ruby aren't "constants". You might as well use any other name; putting them in all caps doesn't change anything, interpreter-wise, about the object, unless you try to change the pointer's address.
If you look at it that way, the behavior is obvious and necessary; Apple is a pointer to a string object, and so is banana. You then edit the object that banana is pointing to. Apple is pointing to that same object, so the change is reflected there too.

What does Ruby constant mean?

What does Ruby constants really mean? The following code doesn't show any 'constant' attribute. The warning is there, but I still get to change what A refers to.
A = 1
puts A # => 1
A = 2 # warning: already initialized constant A
puts A # => 2
Or is Ruby constants are just an indication without any enforcement?
That's right, constants are just like variables in ruby, but you get a warning if you change them.
Also, there's one difference with mere variables: You can access constants even if they are defined inside another class or module, for example given this snippet:
module Constants
PI = 3,1415
other = "variable"
end
You can reach PI doing Constants::PI while Constants::other will not work.
Yes, Ruby constants aren't enforced, other than printing that warning.
That's right -- assigning to a constant is a warning, not an error; "constants" are just an indicator of how you should use something, not a rule that you do use it that way.
That may sound horrendous coming from a static-programming world, but it's immensely useful in various metaprogramming facilities, and it enables things that would otherwise be completely impossible in static languages.
That said, if you really want to make sure people keep their grubby hands off your references, you can use Object#freeze. It's still okay to change what a reference points to with this; you just can't change the contents of the reference itself:
irb(main):001:0> class Fruit; attr_accessor :name; end
=> nil
irb(main):002:0> f = Fruit.new
=> #<Fruit:0xb7e06570>
irb(main):003:0> f.name = "apple"
=> "apple"
irb(main):004:0> f.freeze # After freeze, can't touch this Fruit.
=> #<Fruit:0xb7e06570 #name="apple">
irb(main):005:0> f.name = "banana"
TypeError: can't modify frozen object # Kablammo!
from (irb):5:in `name='
from (irb):5
But this is okay:
irb(main):006:0> f = Fruit.new
=> #<Fruit:0xb7dfed84>
irb(main):007:0> f.name = "banana"
=> "banana"
"Constant" is really a misnomer, the most important aspect of Ruby's "Constants" is not their immutability but their lookup rules.
see: http://coderrr.wordpress.com/2008/03/11/constant-name-resolution-in-ruby/
Constants are used to store values that should not be changed. Their names must start with an uppercase letter. By convention, most constant names are written in all uppercase letters with an underscore as word separator, such as SOME_CONSTANT.
Constants defined within classes can be accessed by all methods of that class. Those created outside a class can be accessed globally (within any method or class).
class Car
WHEELS = 4
def initialize
puts WHEELS
end
end
c = Car.new # Output: 4
Note that Ruby does not stop us from changing the value of a constant, it only issues a warning.
SOME_CONSTANT = "foo"
SOME_CONSTANT = "bar"
warning: already initialized constant SOME_CONSTANT
warning: previous definition of SOME_CONSTANT was here
In Ruby, all class and module names are constants, but convention dictates they should be written in camel case, such as SomeClass.
Constants can be accessed from outside the class, even within another class, by using the :: (double colon) operator. To access the WHEELS constant from outside the Car class, we would use Car::WHEELS. The :: operator allows constants, public instance methods and class methods to be accessed from outside the class or module on which they are defined.
A built-in method called private_constant makes constants private (accessible only within the class on which they were created). The syntax is as follows:
class Car
WHEELS = 4
private_constant:WHEELS
end
Car::WHEELS # Output: NameError: private constant Car::WHEELS referenced
If you're coming from other programming languages, Ruby handles constants differently than what you may be used to. Constants, in general, take values that do not change through the entire application. The syntax is to use all capital letters while naming your constant so that the application knows how to handle it. For example, to set a constant to hold a baseball team you would declare it this way:
TEAM = "Angels"
I know you know this much, bear with me here. Typically, other programming languages will not allow you to change the value of TEAM. However, Ruby does not hold you back and takes the last value assigned to the constant. In the above example, I can change its value to:
TEAM = "Athletics"
Other programming languages would either throw an error or would print the value of Angels. However, Ruby prints the value Athletics because that is the last value assigned to the variable TEAM. Also, it gives a warning message that says that the constant was already initialized and was changed because changing a constant is considered a poor programming practice. But, it still allows you to make the change and follows the Ruby convention of trusting the developer to make the right programming decision. So, be careful while using constants in Ruby since they can be overridden.

Resources