Here @board
is an instance variable. Instance variables belong to an object (instance), hence why they are called instance variables.
You have two references to an instance variable named @board
in your code. Now, ask yourself: which object do they belong to? In other words: what is self
at the point where you reference the instance variable?
class GameRunner
# Here, `self` is `GameRunner`
@board = Board.new
def getBoard
# Here, `self` is an *instance* of `GameRunner`
@board
end
end
At the first reference to @board
, self
is the GameRunner
class itself. Remember, class are objects just like any other object; they are instances of the Class
class just like strings are instances of the String
class, integers are instances of the Integer
class, and game runners are instances of the GameRunner
class.
You can easily see that the instance variable has been defined and initialized:
GameRunner.instance_variables
#=> [:@board]
GameRunner.instance_variable_get(:@board)
#=> #<Board:0x0000deadbeef1230>
At your second mention, however, self
is an instance of GameRunner
, and not the GameRunner
class itself.
Or, to put it differently: you have two completely independent instance variables of two completely independent objects. The instance variables just happen to have the same name.
It's exactly the same as if you did:
game_runner1 = GameRunner.new
game_runner2 = GameRunner.new
The instance variables of game_runner1
and game_runner2
are private to each of those two objects. game_runner1
does not know anything about the instance variables of game_runner2
and vice versa. The same thing is true about game_runner1
and GameRunner
.
Again, it is important to remember that classes are just objects like any other object.
It looks like what you actually want is to have both references refer to the same instance variable, namely an instance variable of an instance of GameRunner
. You can achieve that by moving the assignment into an instance method, something like this:
class GameRunner
def initializeBoard
# Here, `self` is an *instance* of `GameRunner`
@board = Board.new
end
def getBoard
# Here, `self` is an *instance* of `GameRunner`
@board
end
end
However, this is somewhat annoying because you always have to remember to call initializeBoard
before you can use the object, and you have to make sure that once you have called initializeBoard
, you never call it again.
To make initialization tasks like this easier, Ruby has a convention: the default implementation of Class#new
will call a method named initialize
on the newly allocated object:
class Class
def new(...)
obj = allocate
obj.initialize(...)
obj
end
end
[This is not quite accurate because initialize
is private by default, so it would be more like obj.__send__(:initialize, ...)
, but you get the idea.]
So, if we simply rename the initializeBoard
method to initialize
, that will ensure that our instance variable is always initialized by GameRunner::new
:
class GameRunner
def initialize
# Here, `self` is an *instance* of `GameRunner`
@board = Board.new
end
def getBoard
# Here, `self` is an *instance* of `GameRunner`
@board
end
end
Note that your code violates multiple Ruby community coding standards:
- Ruby uses 2 spaces for indentation, not 4.
- There should be no empty line after
class
or before end
- Method names use
snake_case
, not camelCase
. IOW, your getter method should be called get_board
.
- … Except it shouldn't, because getters should simply be called
noun
, not get_noun
, i.e. your getter method should be called simply board
.
- Lastly, trivial getters should not be defined by hand, but using the core
Module#attr_reader
method.
If we combine all of this, your class should look like this:
class GameRunner
attr_reader :board
def initialize
@board = Board.new
end
end
I, personally, prefer to avoid referring to instance variables directly as much as possible, and only use getters and setters. However, that is not a majority coding style, that is just my personal preference:
class GameRunner
attr_reader :board
private
def initialize
self.board = Board.new
end
attr_writer :board
end