Ruby Quirk – the .shift method when manipulating arrays

One of the principles behind Ruby is the Principle of Least Surprise. So far, in my two months of joy learning and working with Ruby (mostly with the code acting as the backbone behind my primitive text layout engine–like a very very primitive alternative to LaTex), I’ve relied on this principle quite heavily–and successfully. But today, for the first time, I was very unpleasantly surprised.

I’m using the latest stable release of Ruby, version 1.8.6-p111 on Windows. I’ve recreated the same “error” or “bug” using the online live preview of Ruby on Ruby’s home website.

The code:

irb(main):001:0> x = [1,2,3,4]
=> [1, 2, 3, 4]
irb(main):002:0> x.shift.nil?
=> false
irb(main):003:0> x
=> [2, 3, 4]

Am I missing something here? I thought that the .nil? method was always nondestructive! (And that the only kinds of methods that permanently change something always end in “!” like “.gsub!”. Even if I used it as a conditional statement, like, “if x.shift.nil? … “, the use of that statement alone would alter the x array!

I’m pretty sure all the Ruby developers are aware of this–it’s just too blatant. My only suggestion to them is–this kind of behavior seems completely against the, you guessed it, Principle of Least Surprise.

UPDATE June 16, 2010: Apparently, after learning shell scripting, it has dawned on me that the “shift” command is an old shell built-in command that destructively removes the first element of the array (in zsh, bash, etc.). This is probably why Ruby did not bother with “shift!”. Still, if I were Matz, I would have favored uniformity over preserving old traditions — and my original post’s message still rings true to me. Of course, the safe alternative to x.shift.nil? is x[0].nil? — simply accessing the first element at index 0 instead of using shift.

Advertisements

5 thoughts on “Ruby Quirk – the .shift method when manipulating arrays

  1. I totally agree with you, the design of this “shift” method is more than strange.

    Say you do
    #x=[1,2,3,4,5]
    #y=x
    #x.shift
    #y
    => [2,3,4,5]

    Maybe there are reasons for this, but for me, as a long term Lisp programmer, this is almost a design flaw in Ruby ! 😦

  2. Hi LaP,

    Hmm, I was not aware of this behavior. It looks like the variable y is acting like a pointer. You can avoid that behavior by assigning y with x.dup instead of just x.

  3. @Shinobu:
    In fact it looks they wanted to mimmic the behaviour of “shit” in sh/bash, which is destructive.
    But for a generalistic modern programming language as ruby tends to be, this looks like weird…

    Regarding the implementation, yes you can consider x and y here are pointers. As “shift” actually changes the contents of the array, 1)It should have been named `shift!’, 2)this explains why `y’ in my example gets its contents changed.

    As I faced a bug which took me some time to solve, before deciding to check the behaviour of `shift’ then realizing my error, I decided to post here. Hope this could help some other rubyist 🙂

  4. Correction : They did not want to mimmic “shit” but “shift”. Of course. Please excuse my typo.

Comments are closed.