I was looking @ moving some code for a project that was started in C# to Ruby. 1stly, it is astounding how much less code it takes to do the same stuff. That however is not the reason I chose to post this morning.
Gabe and Micah are playing nicely together today (it is nice when a 3 and 5 year old brothers can get along so well). I have been fiddling with this code on the sofa and while moving my code, I came to move a c# Equals(object) method and the counterpart GetHashCode(). ReSharper is a great tool – it had given the basis for these overrides. Simple Alt+Insert gives you the ‘generate’ menu and from there you can ask it to generate these methods for you. Essentially – you tell ReSharper the fields that must be ‘unique’ and then it can handle the Equals and GetHashCode methods for you.
Here is what I had in my c# code:
Now this is fine (not exactly) for my C# application as I see it. ReSharper kindly churned out the code I needed also – which is great. When I moved it into ruby however, it looked very un-ruby. Astute readers will also notice that the implementations of Equals and GetHashCode do not match – the Alias property was added later, included in the Equals but NOT in the GetHashCode . Generating code has its issues it would seem.
One of the areas that ruby excels at is helping you write less code. Part of that is identifying the little repeated bits in your code and automating it away with a little ruby.
So what is the pattern above? Well – equals checks for null, checks for direct object reference comparison, then checks a number of fields. It also does a type check. Then it compares a number of fields. If any of these fields fails comparison – it returns false. Ruby does not really need the type check, it just says ‘if you have these props then you are fine by me’ (duck typing).
The folks @ JetBrains recognized the pattern – based on the input of what properties are unique, it generates a code snippet. In ruby, we will not generate code, but handle it like this:
Here include a module called SymbolHashEquals. In this module I define 2 methods symbol_hash and symbol_eql?. These methods take a list of attributes and then apply the same logic that resharper generated. This uses ruby’s symbols that allow you to refer to elements by the ‘name of the code’ or … symbol.
In stead of having our class generate methods based on a heuristic or 2, we simply make a module that holds that abstraction, then we include it, and have our host class use it. Essentially, since ruby lets you ‘do more with less’ we do not have to ‘generate more code’ – we simply can codify more into our solution and have less dumb, generated code. Instead of investing in software to generate more code, we do less!
Here is our module that works on the symbols and handes the standard eql?and hash.
Now – rather than generating code every time I need that same logical heuristic, I simply include that 1 module, and we are good to go. Less code, less repetition, etc.
There you have it – ruby rocks!