Tuesday, 18 September 2007

Boy do I Love Ruby...

This fact about Ruby isn't a surprise, I just needed to express how much I love that fact that all numbers are objects:

Come to me sweet DSL's! Massage me expressive and terse code constructs! Relieve my angst and pain and potential RSI!

(Sorry. To much Russell Brand on the plane this morning...)

Even More Ruby Surprises - Blocks and Closures 101

For me, the Ruby learning continues apace. This weekend it was the turn of blocks and closures, however first I'd like to mention a little pecadillo which made me smile.

Surprise C1 - Parallel Assignment

Now those Ruby folks constantly bang on about how expressive Ruby is and generally then go off into very complicated and convoluted discussions as to why, but this, to me is a perfect illustration:

What this says to me is "I have some variables. I want to call them this and this, and I want them to equal this and this." Simple and legible. Nice

Surprise C2 - Blocks Can Have (Multiple) Parameters Passed to Them and Can Return Values Too

Now coming from a Java background, the whole concept of blocks and closures was a bit of a mystery to me. (Now I do get anonymous inner classes, but frankly the whole Closures debate had me a little confused.) No longer. After a single paragraph in the PickAxe (which I won't restate here, suffice to say you should buy the book) I now see what they're all about and how damn useful they can be. I can also see how useful passing a parameter to a block can be:

And if we combine this with the ability to return a value from a block too:

And how about multiple paramaters? Easy:

All in all, blocks seem really controllable and intuitive (to me at least).

Surprise C3 - Ruby Functions Can React According to Whether They Were Called With a Block or Not

It gets even better. Ruby also allows you to simply code functions which can be called with blocks as well as without. If you call with a block, they can react in their own special way:

Surprise C4 - Ruby Blocks Can Be Closures

What we've seen so far haven't strictly speaking been closures. However, Ruby does allow you to use blocks in such a way that they are - blocks can be passed as arguments, and then assigned to variables as Proc objects, and then exceuted using the Proc#call method. To seal the deal, Ruby makes sure that it remembers the context in which a block was defined. That is to say the value of "self", plus the methods, variables and constants in scope. Behold:

Netbeans 6 Note: The grey squiggles under the start_button and pause_button variables indicates that they have been initialised, but not yet used. Handy eh?

Hasta luego!

Friday, 14 September 2007

More Ruby Surprises (and my first Ruby Disappointment)

I'm still going at the PickAxe book. This time it's arrays...

Ruby Surprise B1 - You can use negative indexes

If I use a negative index as the index to your array, it works, but you count from the right hand end, rather than the left:


Ruby Surprise B2 - No ArrayIndexOutOfBoundsException

If I blow the bounds on my array, I just get a nil, rather than an ArrayIndexOutOfBoundsException equivalent:


Ruby Surprise B3 - Addressing Ranges is Easy

There are a number of ways to get a range of values from my array. The first is to pass in two arguments, the start index and the range size:


Then there is the start index and the end index version...:


Or the start index and the one before the end index version...:


And I can even use the negative indexing paradigm as mentioned in Surprise B1...:


Ruby Dissapointment 1 - You can't Count Backwards Through an Array (but Groovy can)

This works in Groovy (which I am learning from a colleague has a very similar syntax to Ruby) but not Ruby:

Saturday, 8 September 2007

Ruby Surprises - Back to the Beginning with the PickAxe

I've recently bought the famous PickAxe book. The plan? To go back over all I know about Ruby from a different perspective to make sure I understand all the subtleties of the language. Here are some of the surprises so far for me, someone coming from Java land.

Surprise 1 - Classes are Always Open

In Ruby, classes are always open. This means that when you want to add a new method to them, you simply open them (with a new "class ... end") and add the code you require:

Here we've defined a new class "Song" and given it an initializer. Later (just below in fact) we've realised we need to add a "to_s" method. This is simple to do, simply by re opening the definition of Song. Ruby now sees the Song class as being a combination of all that we've defined for it. Therefore, when we run our code we get the following result:

NOTE: You can redefine any class you want, not just ones you've created yourself. This scares some hardcore Java programmers.

Surprise 2 - To Redefine a Subclass, No Need to Restate the Extension

Here we're going to do exactly the same as before with the "Song" example, but now we'll use a Subclass of Song; "KaraokeSong". As you'd expect, the first time we define KaraokeSong, we need to tell Ruby that it extends Song. However, when we re define it to add a "to_s" method, we can treat it simply as the class that it is. Ruby already knows it extends Song:

(Netbeans) Surprise 3 - Netbeans can't do Code Completion on Already Defined Variables in a Class Re-Definition

I guess this is probably too much to ask, but as I'm trying to learn how to use the Netbeans Ruby Editor at the same time as I learn Ruby, it is worth nothing that code completion for variables doesn't work if you are in a piece of code which is re defining a class which contains them:

On the positive side, it is very cool that code completion works within String literals. Regex completion is a godsend too.

Surprise 4 - Slimline Ruby Encapsulation

Anyone who has nearly gone insane hand-coding Javabean encapsulation code without the refactoring help of an IDE will have railed against the verbosity of the getXxxx and setXxxx paradigm. I was pleasantly surprised therefore to discover the simplicity and expressivity of the Ruby encapsulation code:

This to me makes it look as if the attribute is not encapsulated (which makes client code simpler and easier to read) when in fact it is (which means you get all the good points of encapsulation). Cool.

Surprise 5 - You can Encapsulate Virtual Attributes

Using this Ruby encapsulation idiom, you can encapsulate virtual attributes (i.e. ones which do not exist as actual instance variables):

(Netbeans) Surprise 6 - Class Attributes Must be Initialised Before You Use Them

It's a rule that a Ruby class attribute must be initialised before you use it. Netbeans reinforces this by not providing it as an option in code completion if you forget to do so (Though it would be cool if there was an associated tool tip to remind you to follow the rules):

That's it for now. More to follow as I progress through the book...