Classes & Objects

Oscar Romero
5 min readFeb 10, 2021

The topic of these posts are in reference to the Ruby language. Classes and objects are used in Object Oriented Programming (OOP) to encapsulate code to prevent an unwanted changes affecting your program. In other words, code is put in ‘’containers” so that data can only be manipulated by intent and not by accident.

Classes define an object behavior and its state. Behaviors are equivalent to instance methods and States are equivalent to instance variables. Object are described as being an instance of a class. Because every object that belongs to the same class have the same behavior and different state, any changes to that state will only effect that particular object hat was changed.

Classes

Classes define objects, ie an instance object. Think of a class as a blueprint that allows you to make an object, how every many copies you want. Instance objects have the same behavior and their own states. Each object is unique, but it is possible to have states that are the same value. Think of someone who has your same name and age but you both know you are not the same person. Classes are named using CamelCase.

class Elf
attr_reader :name

def initialize(name)
@name = name
end

def use_magic
"#{@name} casts magic missile"
end
end

legolas = Elf.new('Legolas')
drizzet = Elf.new('Drizzet')
puts legolas.name
=> 'Legolas'
puts legolas.use_magic
=> 'Legolas casts magic missle'
drizzit.name
=> 'Drizzet'
drizzet.use_magic
=> 'Drizzet casts magic missle'

Classes have class methods and self is used to define a method definition. Class methods are invoked on the class itself and not an object

class Human
def self.species
'I am a Human'
end
end

bob = Human.new
bob.species
=> NoMethodError (…)
Human.species
=> 'I am an Human'

Classes have class variables and defined using @@, ie @@class_variables. Class variables are scoped within the class itself.

class Human
@@count = 0

def initialize
@@count += 1
end

def self.count
@@count
end
end

bob = Human.new
Human.count
=> 1

Classes and Inheritance

A superclass is a class that passes on behaviors and states and a subclass is a class that inherits the behaviors and states. The symbol < is used to show inheritance during class definition. A superclass can have many subclasses, but in Ruby a subclass can only have one superclass. Anything that is defined in a class including modules and class variables can be inherited, just be aware that subclasses might have an effect on those “items”. Inheritance is a deeper topic and is not completely covered in this post.

class Species
attr_reader :name

def initialize(name)
@name = name
end

def use_magic
"#{@name} casts magic missile"
end
end

class Human < Species
end

class Elf < Species
end

gandalf = Human.new('Gandalf')
gandalf.use_magic
=> 'Gandalf casts magic missile'
legolas = Elf.new('Legolas')
legolas.use_magic
=> 'Legolas casts magic missile'

Classes and Modules

Modules are similar to classes in that they also define behaviors and states but unlike a class cannot create objects. Modules are used in classes using the keyword include. This is called a mixin. Mixins are used when you want to include behaviors and states to a class that already has a superclass. Modules have other attributes but are covered in this post.

module Magic
def use_magic
"#{@name} cast magic missile"
end
end

class Species
attr_reader :name

def initialize(name)
@name = name
end
end

class Human < Species
end

class Elf < Species
include Magic
end

class Dwarf < Species
include Magic
end
aragorn = Human.new('Aragorn')
aragorn.use_magic
=> NoMethodError (..)
arwen = Elf.new('Arwen')
arwen.use_magic
=> 'Arwen casts magic missile'
gimli = Dwarf.new('Gimli')
gimli.use_magic
=> 'Gimli cats magic missile"

Method Lookup

Ruby looks for method in class in a logical order. We can see this order by using the class method #ancestors which returns an array of the searched “objects”. Ruby will search in the calling class first, if any modules are present it will work it way up until all modules are searched, then it will looks for the method in a superclass include any modules in the superclass until the BasicObject is reached, if no method is found it will return with a NoMethodErrror.

module Bark
end
module Swim
end
module Birth
end
class Animal
include Birth
end
class Dog < Animal
include Swim
include Bark
end
Dog.ancestors
=> [Dog, Bark, Swim, Animal, Birth, Object, Kernel, BasicObject]

Objects

An instance object is defined by a class and is typically assigned to a variable to allow instance methods to interface with the object. A new object is created with the initialize method and Class.new, initializeis also known as a constructor method because it is used to construct a new object.

Instance methods are defined inside a class definition. Notice how the method defined does not have the keyword self. self will be the topic of another post.

Instance variables are defined using @, @instance_variable. These variables only exists as long as the object exist.

class Person  
def initialize(name)
@name = name
end

def name
@name
end
end

bob = Person.new('Bob')
bob.name
=> 'Bob' ​

Accessor methods

Accessor methods are method used to describe methods that “access” an instance variable by returning the instance variable or assigns/reassigns an instance variable. If the method only returns the instance variable, its called a getter method. If you want assign/reassign an instance variable, the method is called a setter method.

class Person
def initialize(name)
@name = name
end
# getter
def name
@name
end
# setter
def name=(new_name)
@name = new_name
end
end

Ruby is pretty neat in that it has all these little tricks that easy your coding. One of these is the use of attribute accessors. In the example above we had to write out the getter and setter methods. The accessors methods happen to be named after the instance variable.

attr_accessor creates both the getter and setter methods
attr_reader creates the getter ie “reads” the instance variable
attr_writer creates the setter ie “writes” the instance variable

class Person
attr_accessor :name
attr_reader :age
attr_writer :weight
def initialize(name)
@name = name
@age = 20
@weight = 0
end
def get_weight
@weight
end
end
bob = Person.new('Bob')
bob.name
=> 'Bob'
bob.name = 'Rick'
bob.name
=> 'Rick'
bob.age
=> 20
bob.weight
=> NoMethodError (...)
bob.weight = 200
bob.get_weight
=> 200

Other objects can be assigned to an instance variable. When that happens that is called a collaborator object. The instance variable will be an object with the ability to invoke any available instance methods.

class Wizard
def use_magic
"Magic missile was cast"
end
end
class Person
attr_accessor :name, :role
def initialize(name)
@name = name
end
end

bob = Person.new('Bob')
wizard = Wizard.new
bob.role = wizard
bob.role.use_magic
=> 'Magic missile was cast'

to_s method

All ruby classes have a default to_s method which returns the object when the puts method is used, but what this return is mixed of letters and numbers. We can overwrite the default message to return something is useful to us the programmer.

class Wizard
end
class Person
attr_accessor :name
def initialize(name)
@name = name
end
def to_s
"My name is #{name} and I am not a wizard"
end
end
gandalf = Wizard.new
puts gandalf
=> #<Wizard:0x0000000001d23a38>
bob = Person.new('Bob')
puts bob
=> 'My name is Bob and I am not a wizard'

That is a quick intro into Ruby classes and objects. If anything seems incorrect or could be better described please let me know. Next time we will look into the self method.

--

--