Bart_Judge
Bart_Judge

Reputation: 97

Ruby 2.3.3 The Well Grounded Rubyist - undefined method `balance' for 25:Fixnum

I'm currently going through "The Well Grounded Rubyist 2nd Edition" I'm on page 196 and have been given the following code

class Account
  attr_accessor :balance

  def initialize(amount=0)
    self.balance = amount
  end

  def +(x)
    self.balance += x
  end

  def -(x)
    self.balance -= x
  end

  def to_s
    balance.to_s
  end

end

I've used this in and irb session, like so

2.3.3 :001 > require './account.rb'
 => true
2.3.3 :002 > acc = Account.new(20)
 => #<Account:0x007fccb1834ef8 @balance=20>
2.3.3 :003 > balance
NameError: undefined local variable or method `balance' for main:Object
    from (irb):3
    from /Users/BartJudge/.rvm/rubies/ruby-2.3.3/bin/irb:11:in `<main>'
2.3.3 :004 > acc.balance
 => 20
2.3.3 :005 > acc+=5
 => 25
2.3.3 :006 > acc.balance
NoMethodError: undefined method `balance' for 25:Fixnum
    from (irb):6
    from /Users/BartJudge/.rvm/rubies/ruby-2.3.3/bin/irb:11:in `<main>'
2.3.3 :007 > acc -= 5
 => 20
2.3.3 :008 > acc.balance
NoMethodError: undefined method `balance' for 20:Fixnum
    from (irb):8
    from /Users/BartJudge/.rvm/rubies/ruby-2.3.3/bin/irb:11:in `<main>'
2.3.3 :009 >

Line 4 works the way I expected it work acc.balance However, when I use it again in line 8, i get the following error undefined method `balance' for 20:Fixnum

When I do the following, it works consistently as I expect.

 => true
2.3.3 :002 > acc = Account.new(20)
 => #<Account:0x007f82d1834f18 @balance=20>
2.3.3 :003 > acc.balance
 => 20
2.3.3 :004 > acc.balance
 => 20
2.3.3 :005 > acc.+ (5)
 => 25
2.3.3 :006 > acc.balance
 => 25
2.3.3 :007 > acc.-(10)
 => 15
2.3.3 :008 > acc.balance
 => 15
2.3.3 :009 >

I'm assuming it's something to do with how the methods are being called, but I can't find anything to explain it. Is anyone able to shed some light on the disparity of the results, and why FIXNUM is getting involved. I thought @balance would be an INTEGER.

TIA.

Upvotes: 2

Views: 100

Answers (2)

lacostenycoder
lacostenycoder

Reputation: 11226

Calling balance alone will raise NameError because it's trying to call an object on main which has not been defined. You 'll get the same error if you just call random words like foo or bar. Methods must be called on an object.

Max's answer explains part of the problem. However I would suggest you define your class like this to avoid the bug.

class Account
  attr_accessor :balance

  def initialize(amount=0)
    @balance = amount
  end

  def add(x)
    @balance += x
  end

  def subtract(x)
    @balance -= x
  end

  def to_s
    @balance.to_s
  end

end

Upvotes: 1

max
max

Reputation: 102194

The += and -= assignment operators actually reassign the variable. acc += 1 actually just a shorthand for acc = acc + 1.

And why FIXNUM is getting involved. I thought @balance would be an INTEGER.

Prior to Ruby 2.4 there where two classes - Fixnum and Bignum that represent integers of different sizes.

Ruby 2.4 replaced them with a unified Integer class.

Upvotes: 1

Related Questions