Search code examples
hashnullpointerexceptionreadability

Avoid checking for nil when accessing subelement


This is maybe a more cosmetic problem, but I find it really annoying as I always end up with some ugly code. And readability is always important, right?

I want to check if a value exists in a hash within a hash. So what I do is this.

already_exists_data[:data][:user_id]

But that can get me a nullpointer exception if :data is nil and checking :data might give me a nullpointer if already_exists_data is nil. So what I end up with is this:

if already_exists_data && already_exists_data[:data] && already_exists_data[:data][:user_id]
    # Do stuff
end

Now that's some nasty looking code. Perhaps I should modify the hash to be an object instead. But I keep bumping in to this problem sometimes and was wondering how you guys confront it.

I'm currently coding in Ruby but I've had this problem with multiple other languages.


Solution

  • If I ask my butler to pick up the box of chocolates on the dining room table in Victoria street 34, I ask him just that. I don't want to say: Go find Victoria Street, and, if you find it, please look for number 34, and if you find it ...

    I can do that because he catches his own errors: if he doesn't find the street he will just return empty-handed.

    So you should use a try with an empty exception handler. In pseudo-code:

    try {chocolates = streets("Victoria")(34)("dining room")("table")}

    In languages (like ruby, with some homespun syntactic sugar) where blocks are expressions you might write:

    if try {already_exists_data(data)(user_id)}

    do_stuff

    The language itself can also help: in perl, $streets{Victoria}[34]{dining_room}{table} is undefined when e.g. $streets is. Of course, your butler may come home empty-handed for years before you discover that the address is wrong. The try block solution - and your if .. && .... - have the same drawback: only use them when you really don't care if Victoria Street has a number 34 or not.