KNejad
KNejad

Reputation: 2508

Why does having a large array cause NoMethodError to take longer to be raised

I have the following Ruby code where each instance of BigClass creates a array with instances of BigClass (up until a maximum depth).

class BigClass
  # Increase this depending on your computer performance
  MAX_DEPTH = 8

  def initialize(depth = 0)
    @my_arr = []

    5.times do |i|
      unless depth > MAX_DEPTH
        @my_arr << BigClass.new(depth+1)
      end
    end
  end
end

big_class = BigClass.new

puts "Reaches here"

# This line should throw an error but instead freezes
big_class.blah

puts "Doesn't reach here"

When calling a method which doesn't exist, I expect to receive a NoMethodError pretty much instantly, however, it seems that the larger the contents of the array in big_class the longer it takes for the error to be produced.

Why is this?

A few options I considered:

Something I have noticed is that when it prints "Reached here" if I quit (CTRL-C) it will immediately print out the NoMethodError. So it doesn't seem to be an issue with finding whether or not the method exists, otherwise it wouldn't know that that is the error when I quit.

Upvotes: 2

Views: 45

Answers (1)

KNejad
KNejad

Reputation: 2508

I think I worked it out.

If I override the #inspect method of BigClass it no longer causes an issue. This makes me think that something internally is calling #inspect when handling the error. Since the default inspect will include the instance variables, and call inspect on them as well, if there are many instance variables and they all have many instance variables, then it could take a very long time to process.

The below code shows a version which runs as I would expect:

class BigClass
  # Increase this depending on your computer performance
  MAX_DEPTH = 8

  def initialize(depth = 0)
    @my_arr = []

    5.times do |i|
      unless depth > MAX_DEPTH
        @my_arr << BigClass.new(depth+1)
      end
    end
  end

  def inspect
    "now it works"
  end
end

big_class = BigClass.new

puts "Reaches here"

# Correctly raises an error now
big_class.blah_blah_blah

puts "Doesn't reach here"

Upvotes: 2

Related Questions