Jason Axelson
Jason Axelson

Reputation: 4665

Trying to use Ruby super to call method directly

Consider this code:

class Hello
  def hi
    puts "Hello"
  end
end

class HelloWorld < Hello
  def hi
    super.hi
    puts "World"
  end
end

HelloWorld.new.hi

Gives output:

$ ruby super.rb
Hello
super.rb:9:in `hi': undefined method `hi' for nil:NilClass (NoMethodError)
    from super.rb:14:in `<main>'

Why does Hello get printed? I would expect to just get the error. Also I know that what I really should be doing is just calling super instead of super.hi but I want to understand what is happening "under the hood".

Upvotes: 1

Views: 850

Answers (2)

Arup Rakshit
Arup Rakshit

Reputation: 118271

super.hi is only the method chaining you put inside the class HelloWorld.The call to super is valid,but on return value from super call,is nil due to puts statement.And then nil.hi is the culprit.

class Hello
  def hi
    puts "Hello"
  end
end

class HelloWorld < Hello
  def hi
    super.hi
    puts "World"
  end
end

HelloWorld.new.hi
# ~> -:9:in `hi': undefined method `hi' for nil:NilClass (NoMethodError)

This is because super method is called first,which produces the output Hello,by calling Hello#hi. Now puts "Hello" made the super method to return nil. NilClass don't have the hi method,thus nil.hi throws error. See now the same thing with different taste.

class Hello
  def hi
    p "Hello"
  end
end

class HelloWorld < Hello
  def hi
    super.hi
    puts "World"
  end
end

HelloWorld.new.hi
# ~> -:9:in `hi': undefined method `hi' for "Hello":String (NoMethodError)
# ~>  from -:14:in `<main>'
# >> "Hello"

Here I changed the puts to p,so now as per the convention p "Hello" returns the "Hello" String itself,unlike puts.But the error is definite,as String class don't have the method hi,so the now "Hello".hi throws the legitimate error.

Upvotes: 0

Jorge Israel Pe&#241;a
Jorge Israel Pe&#241;a

Reputation: 38586

super already automatically calls the method that is being overridden. What's happening is that hi in Hello returns nil, because it simply did puts which returns nil (and it's the last expression). So Ruby evaluates super, which calls the method, and then it tries to access the hi method from the resulting nil object, and there is none.

Upvotes: 7

Related Questions