What strategy do I use to avoid global variables in ruby? - ruby

I'm learning Ruby through 'Learn to Program' by Chris Pine. I'm trying to cope without global variables. I have a sloppy looking command prompt blackjack program (can't split yet) My first three methods illustrate the problem I'm having. In Pascal I would have used global variables, and used methods to manipulate those global variables. It would look something like this (using ruby pseudo language)
$deck_of_cards = []
$player_hand = []
$dealer_hand = []
def create_deck
$deck_of_cards = #numbers 1-52
end
def shuffle_deck
$deck_of_cards = #shuffled up deck of cards
end
def opening_deal
2.times do
$player_hand.push $deck_of_cards.pop
$dealer_hand.push $deck_of_cards.pop
end
end
create_deck
shuffle_deck
opening_deal
and I would end up with a shuffled deck, a player hand, and a dealer hand.
Taking away global variables, the first two methods now look like this:
def create_deck deck_of_cards
deck_of_cards = #numbers 1-52
return deck_of_cards
end
def shuffle_deck deck_of_cards
deck_of_cards = #shuffled up deck of cards
return deck_of_cards
end
deck = create_deck([])
deck = shuffle_deck(deck)
which feels a little odd but I could get used to it.
But I'm completely stuck on the last method, which would need to return two variables, player_hand and dealer_hand. I could push those two arrays into another array and return that, but that doesn't seem like it's simplifying anything.
Is there a general strategy for dealing with this, or does each situation have its own unique solution?
Another situation that comes to mind is a chess program. Why would it not make sense to make the chess board a global variable since almost all methods in a chess program would need to use it's value?

The short answer: Objects. Object oriented programming allows you to encapsulate data so that it doesn't pollute the global namespace. As your projects grow larger, it becomes unmaintainable to have all your data in the global namespace. Objects allow you to group data and methods into meaningful units, which can then be re-used and maintained more easily.
So for instance with the example you provided we could make deck and hand objects. This then allows us to create multiple deck and hands easily because these objects encapsulate and manage their data.
As a rough outline of how you might organize your classes / methods:
class Deck
def shuffle
end
def draw_hand
end
end
class Hand
end
class Card
end

In general, using object oriented programming techniques you would define classes and create objects of those classes and then pass around those objects. You can think of objects as sort of like arrays in that they can contain lots of related data, but better than arrays in that the data elements can have names and can be any type and do not need to be the same type and they come with named functions for operating on the data. (Actually, in Ruby, Array elements can be any type and do not need to be the same type, and the same is true of Hash elements plus Hash elements have names, but Ruby is special that way. Few other languages allow that.)
Keeping it simple, though, you can continue your program like this:
def opening_deal deck_of_cards
player_hand = []
dealer_hand = []
2.times do
player_hand.push deck_of_cards.pop
dealer_hand.push deck_of_cards.pop
end
return player_hand, dealer_hand
end
player_hand, dealer_hand = opening_deal deck

It is a bad habit to have global variables, but it is not bad to have global constants, or in other words, constants defined in the main name space. When in need of a global variable, you can always define a constant in the main name space. Mutable objects like string, hash, array can be modified even if it is a constant. If that is not enough and you need more complicated things, then you can define a module (which is a special case of constants), and define methods on that module to have access to the things you want to do, and encapsulate the complicated information inside that module using instance variables.

Related

Calculating a map of instance variables

My module method should return a Hash, where the keys are symbols denoting the instance variables of self and the Hash values are their respective values. I came up with the following solution:
module M
def self.set
#foo = 5
end
def self.ivar_map
Hash[instance_variables.map{|iv| [iv, instance_variable_get(iv)]}]
end
end
M.set
M.ivar_map # => {:#foo=>5}
This works of course, but I wonder whether there isn't a simpler way to achieve the same result. After all, Ruby somehow has to maintain such a symbol table already, mapping the variables to their content.
This works of course, but I wonder whether there isn't a simpler way to achieve the same result.
There are some slight simplifications that you could do:
Use Array#to_h instead of Hash::[].
Use Array#zip.
Use point-free style using Object#method or something like the method reference operator if that is ever added to Ruby.
module M
def self.ivar_map
instance_variables.zip(instance_variables.map(&method(:instance_variable_get))).to_h
end
end
or with the experimental (and removed again in 2.7.0-preview3) method reference operator:
module M
def self.ivar_map
instance_variables.zip(instance_variables.map(&self.:instance_variable_get)).to_h
end
end
After all, Ruby somehow has to maintain such a symbol table already, mapping the variables to their content.
Actually, that is not true. Several Ruby Implementations (including YARV, the most widely-used one) optimize instance variables to some extent. E.g. I believe YARV stores up to three instance variables in the object header directly, without using an instance variable table.
And YARV is on the more simple side when it comes to optimizations. Other implementations like Rubinius, JRuby, TruffleRuby, and RubyOMR perform much more sophisticated optimizations.

how to avoid passing same parameter through multiple methods

def foo(a)
# some computation
bar(a, b)
end
def bar(a,b)
# some computation
baz(a, b, c)
end
def baz(a, b ,c)
print a
end
How to avoid passing same parameter (a) to all methods? One way is to make parameter a as an instance variable. What is the right way to do this?
There is no single solution which works in every case, and often, passing the parameters explicitly is simply the best choice, especially when it comes to debugging.
You can use instance variables, but I would not introduce a new instance variable for the sole reason not to avoid passing it down the call chain. It should have its own value in addition.
One approach which I can see often in projects, is to us a single parameter hash, where the new parameters are added:
def foo(a)
....
bar({a:a, b:b})
end
def bar(par)
....
par[:c] = c
end
def baz(par)
par[:a]+par[:b]+par[:c]
end
This is not without drawbacks either. If you, for instance, forget to "add" a necessary parameter, this will either yield wrong results or throw an exception (depending on how to used them), while forgetting them explicitly via the parameter list, would be found at compile time already.
I would make the decisiion depending on the length of the parameter lists involved. If the number of parameters to a methods is larger than 5, I would start thinking, whether a different design might be more appropriate.
Answering the question stated: yes, ruby is a stateful OO language, having mutable everything. So in ruby one might introduce instance variables:
class MyClass
def foo(a)
#a = a
# some computation
bar(b)
end
def bar(b)
#b = b
# some computation
baz(c)
end
def baz(c)
print [#a, #b, c].inspect
end
end
In the real life, the best practice would be to avoid using instance variables wherever possible, and pass everything across methods. That might save you days of debugging in the future.

Ruby OOP Class Responsibilities

I am still trying in wrap my head around OOP in Ruby. Let's say I'm trying to create a simple Hangman game and I want to select a random word from a text file. So far I have 2 examples in the codeblock. The first example shows a Word and Game class, where the Word class generates a random word and the Game class calls the Word class in the initialize method. The second example has only a Game class where the Game class itself generates the random word. My question is, is it the Game classes responsibility to generate the random word or use the Word class?
# First Example
module Hangman
class Word
def self.words
File.readlines("../words.txt")
end
def self.random
words.select { |word| word.length > 4 && word.length < 13 }.sample
end
end
class Game
attr_reader :random_word
def initialize
#random_word = Hangman::Word.random
end
end
end
# Second Example
module Hangman
class Game
attr_reader :words, :random_word
def initialize
#words = File.readlines("../words.txt")
#random_word = #words.select { |word| word.length > 4 && word.length < 13 }.sample
end
end
end
Sandi Metz has a great example of how to answer this question in Practical Object Oriented Design in Ruby. Sadly, since it is copyrighted I can't link directly to the passage.
In her example, although a bicycle seems like a good candidate for a class due to its obvious existence in the problem domain, at the point in the development of her application that she needs to compute a gear ratio, she realizes that the inputs to that calculation are all related only to gears: the number of teeth on each of two instances of Gear, and thus places the functionality on Gear, deferring the creation of the Bicycle class until a later time.
So the general answer is: look to the input values for the required computation and place that computation's definition on the class with the greatest number of those input values as fields already.
In your specific case:
is it the Game classes responsibility to generate the random word or use the Word class?
Well first off, it seems like your Word class is more of a WordList class, although depending on your future direction, it could remain a Word class but in embodiment of the composite pattern . If you do keep it as a WordList class, it has no instance methods, so discussing responsibilities of the class becomes very difficult. Effectively the class itself has methods, but the class is always expected to be at "singleton instantiation scope" or a constant. Ruby class names are constants, so defining methods only at the level of constants is effectively procedural, not object-oriented, code.
To make WordList object-oriented, you can pass an IO instance (File is a subclass, but why depend on a subclass whose additionally defined methods are not needed by your code?) to WordList#initialize , potentially providing singleton access with a
def self.singleton_instance
#singleton_instance ||= new(File.open("../words.txt"))
end
This allows other clients to reuse the WordList class in other contexts by providing any kind of IO, including a StringIO, and separates and makes explicit that loading the default, singleton WordList is only one way this class expects to be used, requires the constant-scope level file from the parent directory, and allows the instance-level behavior of a WordList to be defined.
So far it looks like that instance-level behavior you need is a random selection from all the words. Getting back to Sandi Metz's advice, WordList does seem like a good place to put the computation of the random selection, because WordList will have a field:
attr_reader :words
def initialize(io)
#words = io.readlines
end
and it's exactly the words field that the filtration is to be performed upon, so this class is a good candidate for that functionality:
def random # notice no self. prefix
words.select { |word| word.length > 4 && word.length < 13 }.sample
end
and later, to actually-use,
#random_word = Hangman::WordList.singleton_instance.random
This also gives you a place to swap-out the singleton instance for a different one if you need to later, without changing the WordList class. That should score points for complying with the Open Closed Principle too.
(An aside: it seems that "random" may be a poor choice for method name -- it's not just random, but also constrained to a length of between 4 and 13 exclusive. Perhaps "random_suitable_length_word"?)
In general it depends.
For this specific case I think most people would agree that splitting the structure between Word and the Game is a good idea.
Word is a nice small testable piece, and so it does deserve its own class.
It also could be reusable in a number of games that need a random word.
I think this becomes clearer if you rewrite word so it has an initialize method. Then the game is simply calling Word.new(...) to get a new random word.
Imagine if there was a gem called "words" that already did all this. You would be happy add the gem and say done deal. Well that is an easy way to tell you have made a good division of labor, even no such gem exists.
By the way once you think this should be a separate class, you might want to check to see if somebody already did it for you. In this case there is a gem random-word.
What would the parameters be to words initialize? Well the length of the word, skill level, etc etc.
class Word
def self.words
#words ||= File.readlines("../words.txt")
end
def initialize(min_length, max_length)
Word.words.select do |word|
word.length > length && word.length < max_length
end.sample
end
end

Ruby initialization idiom using symbols

I'm doing some work in an existing Ruby code base, and I'm quite new to Ruby. I see this initialization idiom pretty often:
def initialize(input)
#number = input[:number]
#color = input[:color]
end
I guess I have two questions. One is whether this is a common idiom and if so, what's good about it? The second is, what is actually happening here? Is the implication that input is an array? A hash? The underlying mechanics aren't clear to me.
Yes, it's common. Generally when you see code like this, it means that input is a Hash. Occasionally someone might pass in an object that acts like a hash, though, and we can still expect this code to work. We can tell that input is definitely not an array, because arrays require Integers to be used as their index, but :number and :color are Symbols.
Whenever you see something starting with a colon like :number, that is a Ruby symbol.
Whenever you see something starting with a # like #number, that is the name of an instance variable. Instance variables are used to store data inside objects for later use.
Suppose we have a class Foo defined like this:
class Foo
def initialize(input)
#number = input[:number]
#color = input[:color]
end
end
In this case, we can create a new object like this:
Foo.new(number: 4, color: 'red')
The code above is equivalent to:
input_hash = { :number => 4, :color => 'red' }
Foo.new(input_hash)
One nice thing about this pattern is that you can tell exactly what each input variable is being used for because it will be written next to a descriptive symbol, and also it doesn't matter what order you put the input variables in.
Improvements
If you want to improve this code, you might consider using a new feature of Ruby called keyword arguments. Alternatively, you might also consider Hash#fetch so you can have more control over what happens when one of the keys is missing, instead of just storing a nil value in your object. I would also recommend that you check the input hash for any unexpected keys and raise an exception if they are found.
Is this a common idiom and if so, what's good about it?
It's not common, but it's acceptable. When there are more than n parameters being passed in, where "n" is often > 3, we should use a hash.
What's good about it? Look at the code. Is it simple and readable? Does it make sense that an input parameter of :number is being assigned to an instance variable of the same name?
what is actually happening here? Is the implication that input is an array? A hash? The underlying mechanics aren't clear to me.
It's a hash where :number and :color are keys.

Why were ruby loops designed that way?

As is stated in the title, I was curious to know why Ruby decided to go away from classical for loops and instead use the array.each do ...
I personally find it a little less readable, but that's just my personal opinion. No need to argue about that. On the other hand, I suppose they designed it that way on purpose, there should be a good reason behind.
So, what are the advantages of putting loops that way? What is the "raison d'etre" of this design decision?
This design decision is a perfect example of how Ruby combines the object oriented and functional programming paradigms. It is a very powerful feature that can produce simple readable code.
It helps to understand what is going on. When you run:
array.each do |el|
#some code
end
you are calling the each method of the array object, which, if you believe the variable name, is an instance of the Array class. You are passing in a block of code to this method (a block is equivalent to a function). The method can then evaluate this block and pass in arguments either by using block.call(args) or yield args. each simply iterates through the array and for each element it calls the block you passed in with that element as the argument.
If each was the only method to use blocks, this wouldn't be that useful but many other methods and you can even create your own. Arrays, for example have a few iterator methods including map, which does the same as each but returns a new array containing the return values of the block and select which returns a new array that only contains the elements of the old array for which the block returns a true value. These sorts of things would be tedious to do using traditional looping methods.
Here's an example of how you can create your own method with a block. Let's create an every method that acts a bit like map but only for every n items in the array.
class Array #extending the built in Array class
def every n, &block #&block causes the block that is passed in to be stored in the 'block' variable. If no block is passed in, block is set to nil
i = 0
arr = []
while i < self.length
arr << ( block.nil? ? self[i] : block.call(self[i]) )#use the plain value if no block is given
i += n
end
arr
end
end
This code would allow us to run the following:
[1,2,3,4,5,6,7,8].every(2) #= [1,3,5,7] #called without a block
[1,2,3,4,5,6,7,8,9,10].every(3) {|el| el + 1 } #= [2,5,8,11] #called with a block
Blocks allow for expressive syntax (often called internal DSLs), for example, the Sinatra web microframework.
Sinatra uses methods with blocks to succinctly define http interaction.
eg.
get '/account/:account' do |account|
#code to serve of a page for this account
end
This sort of simplicity would be hard to achieve without Ruby's blocks.
I hope this has allowed you to see how powerful this language feature is.
I think it was mostly because Matz was interested in exploring what a fully object oriented scripting language would look like when he built it; this feature is based heavily on the CLU programming language's iterators.
It has turned out to provide some interesting benefits; a class that provides an each method can 'mix in' the Enumerable module to provide a huge variety of pre-made iteration routines to clients, which reduces the amount of tedious boiler-plate array/list/hash/etc iteration code that must be written. (Ever see java 4 and earlier iterators?)
I think you are kind of biased when you ask that question. Another might ask "why were C for loops designed that way?". Think about it - why would I need to introduce counter variable if I only want to iterate through array's elements? Say, compare these two (both in pseudocode):
for (i = 0; i < len(array); i++) {
elem = array[i];
println(elem);
}
and
for (elem in array) {
println(elem);
}
Why would the first feel more natural than the second, except for historical (almost sociological) reasons?
And Ruby, highly object-oriented as is, takes this even further, making it an array method:
array.each do |elem|
puts elem
end
By making that decision, Matz just made the language lighter for superfluous syntax construct (foreach loop), delegating its use to ordinary methods and blocks (closures). I appreciate Ruby the most just for this very reason - being really rational and economical with language features, but retaining expressiveness.
I know, I know, we have for in Ruby, but most of the people consider it unneccessary.
The do ... end blocks (or { ... }) form a so-called block (almost a closure, IIRC). Think of a block as an anonymous method, that you can pass as argument to another method. Blocks are used a lot in Ruby, and thus this form of iteration is natural for it: the do ... end block is passed as an argument to the method each. Now you can write various variations to each, for example to iterate in reverse or whatnot.
There's also the syntactic sugar form:
for element in array
# Do stuff
end
Blocks are also used for example to filter an array:
array = (1..10).to_a
even = array.select do |element|
element % 2 == 0
end
# "even" now contains [2, 4, 6, 8, 10]
I think it's because it emphasizes the "everything is an object" philosophy behind Ruby: the each method is called on the object.
Then switching to another iterator is much smoother than changing the logic of, for example, a for loop.
Ruby was designed to be expressive, to read as if it was being spoken... Then I think it just evolved from there.
This comes from Smalltalk, that implements control structures as methods, thus reducing the number of keywords and simplifying the parser. Thus allowing controll strucures to serve as proff of concept for the language definition.
In ST, even if conditions are methods, in the fashion:
boolean.ifTrue ->{executeIfBody()}, :else=>-> {executeElseBody()}
In the end, If you ignore your cultural bias, what will be easier to parse for the machine will also be easier to parse by yourself.

Resources