Classes in Ruby
Ruby is what's called an "object-oriented" programming language, but what does that mean? Is the code there to manipulate real life objects? Is there a sort of virtual Lego set in your computer for building little robots? Sort of. Object-oriented programming lets you model the structure of your overall program on smaller components made of code, which can learn and recall attributes specific to their identities. So instead of just writing code that performs something like "dog barks now", you can have code that actually represents the dog, and have that dog know how to bark. Moreover, using something called a "class", the dog will know how to bark because all objects in the class "Dog" know how to bark. Sound useful? Maybe not yet, but this can give a programmer lots of power in the environments they create.
Let's say you find yourself face-to-face with a Terminator. This is a killing machine. It will decide whether to take you out based on its programming, or more specifically, what functions it executes based on its mission, its target, its environment etc. If you were a post-apocalyptic AI charged with designing a robot to go back in time and kill Sarah Connor, how would you do it? Would you just start by making your T-800 walk until it finds her? How does it know when it's in danger of failing its mission, or coming to harm itself? Your code would quickly become sprawling and unorganized - and maintenance would be a nightmare.
Worse, what if you were future John Connor, and you needed to re-program a captured T-800? Before you send that thing back in time you better make absolutely sure you found every bit of code that directs it to "murder Sarah Connor"! You'd like to tell it to do something like "please don't murder Sarah Connor". Every terminator has a target, right? Yours used to be "Sarah Connor", and you want to change it to "T-1000". How does it know what to do with that information?
The AI who designed the terminator has already built in a target
definition - in fact it's built in to every terminator. The T-800 you captured isn't even the same one that tried to kill your mom in the 80's, it just looks the same. So the T-800 model, like all terminators, is humanoid, can speak, has a target that it hunts etc. - but this particular one has its own unique target. This makes it so much easier to crank out all those fake Arnolds at the end of "Terminator: Salvation" - the software is all set up, you just have to give specific parameters to each instance of your terminator and ship it off!
In Ruby this set of guiding functionalities is called a class. All the terminators know how to cook a fool - that's what they do - they get the blueprint for this from their class: "Terminator". Let's look at a simple Terminator class:
class Terminator
def terminate
puts "Hasta la vista, baby."
puts "(You're totally terminated)"
end
end
Within our definition for the Terminator
class, we have a method to terminate
. We can't do anything with this until we have an object of class Terminator
. So let's make one!
johnny_five = Terminator.new
johnny_five.terminate
=> Hasta la vista, baby.
=> (You're totally terminated)
johnny_five
is an "instance" of an object within the Terminator
class. This means johnny_five
inherits all the capabilities defined by Terminator
and can call on those using "dot notation" like: johnny_five.terminate
. What about those specific individual traits that aren't necessarily shared with every terminator? You can define those as arguments when you create a new instance of the class:
schwartz = Terminator.new("T-800", "Sarah Connor", "Arnold-ness", 8)
Each of those items in the parentheses correspond to a parameter that the object internalized when it "initializes":
def initialize(model, target, skill, scary_scale)
@model = model
@target = target
@skill = skill
@scary_scale = scary_scale
end
Now this new terminator, schwartz
, "knows" that its model
is "T-800", its target
is "Sarah Connor", its skill
is "Arnold-ness"(?), and its scary_scale
is 8. If we like, now we can give the Terminator
class a new method:
def identify
puts "I am a #{@model} terminator sent from the future. I have been programmed to
terminate #{@target} using #{@skill}"
end
So we can inquire of this charming new fellow:
schwartz.identify
=> I am a T-800 terminator sent from the future. I have been programmed to
terminate Sarah Connor using Arnold-ness
Lovely. All those @
symbols before our variables have special meaning for our object. These demark "instance variables", meaning they are accessible within the definition of the class, and can be called upon by our object (schwartz
) for its "instance methods". These are just methods that can be called by our instance. So identify
is an instance method, which can access instance variables @model
, @target
and @skill
to have custom functionality for our instance.
What about that last instance variable, @scary_scale
? Just for fun, we can use this as a ranking for a short survival game. Here's the instance method we can call:
def how_dead_are_you
if @scary_scale > 8
puts "You're toast, don't even think about trying to save the future."
terminate
elsif @scary_scale > 4 && @scary_scale <= 8
puts "Action sequence!"
death_chance = rand(10)
sleep(1)
if death_chance + @scary_scale > 9
puts "You've failed, Skynet goes live."
terminate
else
puts "You've escaped ... until the sequel."
end
else
puts "This must be the T-X model, from Terminator 3. Feel free to take a nap."
end
end
So it looks like the higher we set @scary_scale
the less chance we make it out alive because terminate
is called.
I hope this post has been just instructive enough to get you comfortable with how classes work in Ruby, but not instructive enough to allow you to build your own terminator to send back in time and prevent me from writing this. Hasta la vista.
