
I just couldn't resist. Am I talking about Britney Spears here, though? NO! I'm talking Object-Oriented Programming! This week I started reading Practical Object-Oriented Design in Ruby (affectionately nicknamed 'POODIR') and it has blown my mind. The concept here is simple: EVERYTHING IN RUBY IS AN OBJECT! So it's all about making sure the objects are being used correctly, in the right order, and pointing to the right things.
Well... there is something that is NOT an object in Ruby. And that's a block. I'm going to go into Bloc, Proc, and Lambdas You may have seen a block look like this in your programming... a ver common example:
array = [1,2,3,4]
array.each {|x| puts x}
=> 1
=> 2
=> 3
=> 4
The "block" part of it is this: {|x| puts x}
That block is NOT an object... it's simply a block! But there's an "Object" version of this called a Proc
array = [1,2,3,4]
pr = Proc.new {|x| puts x}
***OR*** pr = proc{|x| puts x}
array.each (&pr)
=> 1
=> 2
=> 3
=> 4
See that magic!? The "&" executes the block provided by the Object "pr" that we defined. Without the "&", the "pr" alone is just an argument, and the terminal will be like "WTF was that?".
Another cool thing with Proc is that it can do this with symbols:
array = ["David", "Brown"]
#instead of this:
array.map {|str| str.capitalize}
#you can do this:
array.map(&:capitalize)
=>["DAVID", "BROWN]
I know. It's total sorcery. The "&" character executes the method on an Proc object it sort of "figures out" based on what's there. It goes "Oh, he wants this to be a block, and there's elements, so I'll just do this method to all the elements". Rad, I know.
The last bit is a Lambda. This in the same class as Proc, only with small differences. Very small. Here's how it's made:
lam = lambda{block}
***OR***
lam = -> {block}
Just like a Proc for that first example, but the second example has that fun "Stabby Lambda" construction. No joke, that's what it's called. The difference between Lambda and Proc is, you can't do that fancy symbol thing. And it's finicky about arguments:
lam = lamda {|x| p x}
lam.call(1)
=> 1
lam.call
ArgumentError: wrong number of arguments(0 for
1)
That fancy example is courtesy of "The Well-Groundeded Rubyist" by David A. Black. As you can see, it didn't like that the right number arguments wasn't put in, where with a Proc, it couldn't give a rat's behind. It'll return SOMETHING, even if it's nil. Also, "return" doesn't work out the same way in each... here's another great example from the GOOD BOOK:
def return_test
l = lambda {return}
l.call
puts "Still here!"
p = Proc.new {return}
p.call
puts "You won't see this message!"
end
return_test
=>"Still here!"
Why didn't we see the other message? If you'll recall, "return" in a method EXITS the method, usually. In Proc, this applies, but in lambda, return just exits the block it's in and goes back to the rest. This can be useful, but try to use "return" in a Proc that ISN'T in a method, and you get an error. So sayeth the good book.
Well I hope that was insightful! I can't wait to try to use these in my own coding! I can think of a few examples where I repeated the same block that might could use a refactoring where I define a Proc with the Block I want to ROCK! OK I'm done...