Why is it bad?
Global state is bad for a couple of reasons you didn't mention:
- It's Unreliable: Because anything in your program, including third party code, can change the variable, you can never depend on something being there one second after you put it in.
- It breaks encapsulation: If have a global list of users, other parts of the program should have to go through the User class to access it. Otherwise, everyone is manipulating data directly, which is a bad idea.
- Hard to change: If you find out that your global state needs to be, say, an array instead of a hash, bad luck. You have to change every part of the code that uses it because there are no accessors to change.
- This one is a little more abstract, but still: Function Purity: When you introduce global state, many previously pure functions become impure. This is bad in general, because compiled languages like C can heavily optimize pure functions, and bad in Ruby because it makes methods much harder to test.
The specific form of global state you mention, @@
variables, is also bad for a Ruby specific reason:
- It has weird inheritance semantics:
@@
variables in Ruby are shared between a class and all it's subclasses. So even though you think that it is encapsulated, it isn't. This is especially bad if someone subclasses yourUser
class, and declares a variable@@list
for storing unrelated data. Ruby won't complain, and the state of the entire User class tree is compromised.
What else can be done?
- Dependancy Injection: Just pass around the data to whoever needs it without ever maintaining it globally.
Class Encapsulation: If you need global state, have a class maintain it with setters and getters. This invalidates points 2 and 3, along with the
@@
probelm because it uses class@
variables. Example:class User class << self @list = {} def add_user(uid, user) #Do validation here @list[uid] = user end #More methods like add_user end def initialize(user_id, ...) User.add_user(user_id, self) end end