solid_assert: A simple Ruby assertion utility

2011-09-19

I have published a tiny Ruby gem implementing an assertion utility: solid_assert.

When I started with Ruby I searched about an assert utility. My brother taught me about them a long time ago and I have used them since then. For some reason, assertions are not very used in Ruby. Most rubyists and most famous Ruby libraries just don’t use them. I found the same thing with dependency injection frameworks. But, while after a time working with Ruby I was convinced that I didn’t need a dependency injection framework, I still miss assertions when programming Ruby.

Motivation

The motivation of assertions are very well syntheitzed in the tip 33 of The Pragmatic Programmer book:

If it can’t happen, use assertions to ensure that it won’t

The premise of an assertion utility is very simple: being able to include tests for your assumptions inside your code. This way, it is the program itself who verifies its own integrity. In the same way it is a good practice to use properly named and composed methods so you don’t have to document with comments what some code is doing, it is a good practice to formally code the assumptions you make about your code, and have these assumptions tested automatically.

You may think that regular tests are already covering code integrity. To me, good test suites and assertions are totally complementary. I use tests but I still want my code to launch a nice NoMethodError for NilClass when I try to send a message to a nil reference. In the same way, you can write tests and also build-in integrity checking inside your code using assertions.

An example

Let me show you an example. Imagine you don’t know that Rails already includes an OrderedHash class and you decide to implement your own one.

A simple approach (in fact, the one used by Rails’ OrderedHash) would be extending the Ruby Hash class, using an array of keys for storing the keys in order and delegating hash-related behaviour to its parent class.

For example, we could implement the []= method for setting values in the hash in the following way:

class OrderedHash < ::Hash
    ...
    def []=(key, value)
        @keys << key if !has_key?(key)
        super
    end
    ...
end

The method stores the key in the array and then invoke the parent’s behaviour. Under any circumstance, it should always be verified that the keys array and the hash entries have the same size. That is a class invariant. assert let you express that:

def []=(key, value)
    @keys << key if !has_key?(key)
    super
    assert @keys.size == self.size, "#{@keys.size} elements in the list and #{self.size} entries in the hash?"
end

solid_assert also includes an invariant method that let you make more complex calculations using a block.

invariant do
    one_variable = calculate_some_value
    other_variable = calculate_some_other_value
    one_variable > other_variable
end

Assertions can be disabled. In fact, both assert and invariant are empty methods when you use the lib. You can enable them with SolidAssert.enable_assertions. This let you deactivate them in production, if you are concerned about their performance impact.

References

All the references to assertions you find in books refer directly or indirectly to Bertrand Meyer’s design by contract proposal:

  • The Pragmatic Programmer From Journeyman to Master. It contains a section dedicated to Design by contract and a short one dedicated to Assertive Programming. It says that you can use assertions to partially emulate design by contract. These sections are in the chapter Pragmatic Paranoia, when they defend that:

    But Pragmatic Programmer take this a step further. They don’t trust themselves, either.

    By the way, they recommend you to leave assertions on in production, eloquently saying that turning them off is “like crossing a high wire without a net because you once made it across in practice”.

  • Code Complete. It dedicates a section in the chapter Defensive programming to assertions. It recommends you to use assertions to document and verify preconditions and postconditions in your software.

  • Writing solid code. This was my first reading about assertions and the one that pays more attention to them. In the chapter Assert Yourself it defines assertions, explains its motivation and shows when to use them using many C samples. A great book on good coding practices in general.

  • Programming with assertions. Although it was published for explaining the assert keyword introduced by Java 1.4, it explains very well the underlying concepts and shows many examples using them.

Conclusion

In my experience assertions used reasonably are good. They make your code more solid. You don’t have to check all the invariants, or try to validate all the preconditions and postconditions of every method you write. Just use them when you find yourself saying “at this point this should be verified…” and you will enjoy its benefits in the form of more robust code and less surprises.

I also think that asserts are suitable for any programming language. Of course, with lower level languages like C their use is even more recommended, because errors are more obscure and their consequences are harder to debug. But nothing prevent higher level languages from benefitting from them.

There are 2 comments in this article:

  1. 2013-04-23Gail Houston say:

    does the same thing as the above program. The attr_accessor method is run at read time, when ruby is constructing the class object, and it generates the foo and foo= methods.

  2. 2014-04-18www.vegabaja.net say:

    Hurrah! At last I got a weblog from where I be capable of really take helpful facts concerning my study and knowledge.

Write a comment: