Output not clear

I am a newbie to Ruby and the output of the following program is not clear
to me.

The program is:

class Accounts
  attr_accessor :balance

  def initialize(name, phone, op_balance)
    @name = name
    @phone = phone
    @balance = op_balance
  end

  def deposit(amt)
    @balance += amt
    puts @balance.to_s
  end
end

class Savings<Accounts
  def initialize(name, phone, op_balance)
    super
  end

  def withdraw(amt)
    @bal = balance
    if ((@bal - amt) > 500.00)
      balance = @bal - amt
      puts balance.to_s
    else
      puts 'No Balance'
    end
  end
end

s = Savings.new('Pete',65241884,5000.00)
s.deposit(500.00)
s.withdraw(200.00)
puts s.balance.to_s

The output I get is:

ruby accounts.rb

5500.0
5300.0
5500.0

Exit code: 0

I thought that the last line puts s.balance.to_s would have displayed 5300.0.
Why is this 5500.0 ?

All help appreciated.

  def withdraw(amt)
    @bal = balance
    if ((@bal - amt) > 500.00)
      balance = @bal - amt
      puts balance.to_s
    else
      puts 'No Balance'
    end
  end
end

s = Savings.new('Pete',65241884,5000.00)
s.deposit(500.00)
s.withdraw(200.00)
puts s.balance.to_s

The output I get is:

>ruby accounts.rb
5500.0
5300.0
5500.0
>Exit code: 0

I thought that the last line puts s.balance.to_s would have displayed 5300.0.
Why is this 5500.0 ?

Because you do not change @balance in your withdraw method.

Regards,
Rimantas

···

--
http://rimantas.com/

Greetings

In your withdraw-method it's not really fitting to use @bal as a class
variable. It's not needed outside the scope of a single withdraw, and as
such you don't need to store it's value.

Actuall you don't need it at all, you can instead go for:
  
  def withdraw(amt)
    if ((balance - amt) > 500.00)
      self.balance -= amt
      puts balance
    else
      puts 'No Balance'
    end
  end

While we're at it, I prefer to separate calculations from output to
screen, and instead go for:

  def withdraw(amt)
    raise "You're broke" if balance - amt <= 500
    self.balance -= amt
  end

combined with:

  s.withdraw(200.00)
  puts s.balance

This does withdraw in one place and shows balance in another.

If you now do multiple withdraws, sooner or later you will raise the
"You're broke" run-time error. Which you then have to catch. Unless you've
read about ruby's exception handling you're in for a treat. Exception
handling is very handy, and as always, Ruby does it in an consistent and
intuitive way.

Good luck

···

--
Jon Egil Strand
Phone: +47 98232340
jes@luretanker.no

More confusion. I thought that the statement balance = @bal - amt in the
withdraw method is actually the set method for the @balance variable of the
Accounts class. Is not the set method inherited in the Savings class?

···

On 11/3/06, Rimantas Liubertas <rimantas@gmail.com> wrote:

> def withdraw(amt)
> @bal = balance
> if ((@bal - amt) > 500.00)
> balance = @bal - amt
> puts balance.to_s
> else
> puts 'No Balance'
> end
> end
> end
>
> s = Savings.new('Pete',65241884,5000.00)
> s.deposit(500.00)
> s.withdraw(200.00)
> puts s.balance.to_s
>
> The output I get is:
>
> >ruby accounts.rb
> 5500.0
> 5300.0
> 5500.0
> >Exit code: 0
>
> I thought that the last line puts s.balance.to_s would have displayed
5300.0.
> Why is this 5500.0 ?

Because you do not change @balance in your withdraw method.

Regards,
Rimantas

Thanks. This is a much better code. One more related thing that confuses me
is that I thought all instance variables of a class are private to the
class. Then are the private instance variables inherited by a sub-class? If
yes, then in my Savings class withdraw method, can I write @balance -= amt
instead of self.balance -= amt ?

···

On 11/3/06, Jon Egil Strand <jes@luretanker.no> wrote:

In your withdraw-method it's not really fitting to use @bal as a class
variable. It's not needed outside the scope of a single withdraw, and as
such you don't need to store it's value.

Actually you don't need it at all, you can instead go for:

  def withdraw(amt)
    if ((balance - amt) > 500.00)
      self.balance -= amt
      puts balance
    else
      puts 'No Balance'
    end
  end

While we're at it, I prefer to separate calculations from output to
screen, and instead go for:

  def withdraw(amt)
    raise "You're broke" if balance - amt <= 500
    self.balance -= amt
  end

combined with:

  s.withdraw(200.00)
  puts s.balance

This does withdraw in one place and shows balance in another.

If you now do multiple withdraws, sooner or later you will raise the
"You're broke" run-time error. Which you then have to catch. Unless you've
read about ruby's exception handling you're in for a treat. Exception
handling is very handy, and as always, Ruby does it in an consistent and
intuitive way.

--
Jon Egil Strand

More confusion. I thought that the statement balance = @bal - amt in the
withdraw method is actually the set method for the @balance variable of the
Accounts class. Is not the set method inherited in the Savings class?

This is true. However in the case something = some_value Ruby sees it
as assignment to local variable. In this case you want self.balance =
@bal - amt
instead of balance = @bal - amt.

Regards,
Rimantas

···

--
http://rimantas.com/

sure. the difference is whether you're getting the var from the inside
(@balance) or outside (self.balance)

@balance will be a tiny bit faster, self.balance is more flexible as
you can change the inner implementation later without breaking other
things (i.e. you can add conditions checking befor the var is actually
set)

···

On 11/3/06, Learning Ruby <learningruby@gmail.com> wrote:

On 11/3/06, Jon Egil Strand <jes@luretanker.no> wrote:
>
> In your withdraw-method it's not really fitting to use @bal as a class
> variable. It's not needed outside the scope of a single withdraw, and as
> such you don't need to store it's value.
>
> Actually you don't need it at all, you can instead go for:
>
> def withdraw(amt)
> if ((balance - amt) > 500.00)
> self.balance -= amt
> puts balance
> else
> puts 'No Balance'
> end
> end
>
> While we're at it, I prefer to separate calculations from output to
> screen, and instead go for:
>
> def withdraw(amt)
> raise "You're broke" if balance - amt <= 500
> self.balance -= amt
> end
>
> combined with:
>
> s.withdraw(200.00)
> puts s.balance
>
> This does withdraw in one place and shows balance in another.
>
> If you now do multiple withdraws, sooner or later you will raise the
> "You're broke" run-time error. Which you then have to catch. Unless you've
> read about ruby's exception handling you're in for a treat. Exception
> handling is very handy, and as always, Ruby does it in an consistent and
> intuitive way.
>
> --
> Jon Egil Strand
>

Thanks. This is a much better code. One more related thing that confuses me
is that I thought all instance variables of a class are private to the
class. Then are the private instance variables inherited by a sub-class? If
yes, then in my Savings class withdraw method, can I write @balance -= amt
instead of self.balance -= amt ?

Hi --

In your withdraw-method it's not really fitting to use @bal as a class
variable. It's not needed outside the scope of a single withdraw, and as

@bal is an instance variable, not a class variable.

Thanks. This is a much better code. One more related thing that confuses me
is that I thought all instance variables of a class are private to the
class. Then are the private instance variables inherited by a sub-class? If
yes, then in my Savings class withdraw method, can I write @balance -= amt
instead of self.balance -= amt ?

The terminology is getting a bit convoluted here. Instance variables
are per-object, not per-class, and they're not inherited. But if a
method uses one, and that method is available to subclasses, then it
will still use the variable -- but "the variable" in the sense of one
per object:

   class C
     def initialize
       @n = 100
     end

     def increase_n
       @n *= 20
     end

   end

   class D < C
     def show_n
       puts "n is #{@n}"
     end
   end

   d = D.new
   d.increase_n
   d.show_n

The output is:

   n is 2000

The @n in D's methods is the same (for each instance) as the one in C.

As for the @balance -= thing: you can do that, but sometimes there are
good reasons not to. You might have a balance or balance= method that
does more than just get and set the instance variable. Imagine
something like:

   def last_name=(n)
     @last_name = n.downcase.capitalize
   end

If you now say: @last_name = "bLaCk", it won't get normalized. (And
yes, I know that there's no one rule that governs all last names :slight_smile:
In such a case, it's better to go through the method: self.last_name =
"bLaCk".

David

···

On Fri, 3 Nov 2006, Learning Ruby wrote:

On 11/3/06, Jon Egil Strand <jes@luretanker.no> wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Thanks. That clarified my confusion. One more related thing that confuses me
is that I thought all instance variables of a class are private to the
class. Then are the private instance variables inherited by a sub-class? If
yes, then in my Accounts program, there is no real need to the write the
attr_accessor statement?

···

On 11/3/06, Rimantas Liubertas <rimantas@gmail.com> wrote:

> More confusion. I thought that the statement balance = @bal - amt in the
> withdraw method is actually the set method for the @balance variable of
the
> Accounts class. Is not the set method inherited in the Savings class?

This is true. However in the case something = some_value Ruby sees it
as assignment to local variable. In this case you want self.balance =
@bal - amt
instead of balance = @bal - amt.

Regards,
Rimantas

fathom the difference between @balance and self.balance as mentioned by you
(Jan Svitok) above. Does not the self.balance mean the instance variable
balance of current object? And is not @balance the same thing?

···

On 11/3/06, Jan Svitok <jan.svitok@gmail.com> wrote:

> Thanks. This is a much better code. One more related thing that confuses
me
> is that I thought all instance variables of a class are private to the
> class. Then are the private instance variables inherited by a sub-class?
If
> yes, then in my Savings class withdraw method, can I write @balance -=
amt
> instead of self.balance -= amt ?

sure. the difference is whether you're getting the var from the inside
(@balance) or outside (self.balance)

@balance will be a tiny bit faster, self.balance is more flexible as
you can change the inner implementation later without breaking other
things (i.e. you can add conditions checking befor the var is actually
set)

Coming from a Java background the confusion still exists. I still can't

Hi --

> Thanks. This is a much better code. One more related thing that confuses
me
> is that I thought all instance variables of a class are private to the
> class. Then are the private instance variables inherited by a sub-class?
If
> yes, then in my Savings class withdraw method, can I write @balance -=
amt
> instead of self.balance -= amt ?

sure. the difference is whether you're getting the var from the inside
(@balance) or outside (self.balance)

@balance will be a tiny bit faster, self.balance is more flexible as
you can change the inner implementation later without breaking other
things (i.e. you can add conditions checking befor the var is actually
set)

Coming from a Java background the confusion still exists. I still can't

fathom the difference between @balance and self.balance as mentioned by you
(Jan Svitok) above. Does not the self.balance mean the instance variable
balance of current object? And is not @balance the same thing?

It all starts with the instance variable, @balance. The balance
method is simply a wrapper around it:

   def balance
     @balance
   end

There's no special link between the names; you could also write:

   def my_balance
     @balance
   end

and then do:

   obj.my_balance

It's just a method whose return value happens to be the current value
of an instance variable.

Then there's the other half: the setter-method. Same thing: it's just
a wrapper:

   def balance=(value)
     @balance = value
   end

Again, there's no magic in the naming; you could also do:

   def change_balance_to(value)
     @balance = value
   end

It's customary in such cases, however, to name the get and set methods
with the same name as the instance variable they get and set. In
fact, this idiom:

   def something
     @something
   end

   def something=(value)
     @something = value
   end

is so common, that Ruby gives you a shortcut: instead of writing those
lines of code, you can just do:

   attr_accessor :something

and Ruby will write the methods for you. That's what you've done with
"balance".

One way or another (manually or with an attr method), you have to
define these methods; you can't just say "obj.blah" and expect to get
the value of @blah.

David

···

On Fri, 3 Nov 2006, Learning Ruby wrote:

On 11/3/06, Jan Svitok <jan.svitok@gmail.com> wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Learning Ruby wrote:

One more related thing that
confuses me
is that I thought all instance variables of a class are private to the
class. Then are the private instance variables inherited by a sub-class? If
yes, then in my Accounts program, there is no real need to the write the
attr_accessor statement?

That's a ruby idiosyncratism. Access restrictions operate on an object
level, not a class level. (It's also simpler to implement for instance
variables.)

David Vallner

coincidence that just the other day I bought and have started reading your
excellent book Ruby for Rails - a must for every Ruby beginner.

···

On 11/3/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

Hi --

On Fri, 3 Nov 2006, Learning Ruby wrote:

> On 11/3/06, Jan Svitok <jan.svitok@gmail.com> wrote:
>>
>> > Thanks. This is a much better code. One more related thing that
confuses
>> me
>> > is that I thought all instance variables of a class are private to
the
>> > class. Then are the private instance variables inherited by a
sub-class?
>> If
>> > yes, then in my Savings class withdraw method, can I write @balance
-=
>> amt
>> > instead of self.balance -= amt ?
>>
>> sure. the difference is whether you're getting the var from the inside
>> (@balance) or outside (self.balance)
>>
>> @balance will be a tiny bit faster, self.balance is more flexible as
>> you can change the inner implementation later without breaking other
>> things (i.e. you can add conditions checking befor the var is actually
>> set)
>>
>> Coming from a Java background the confusion still exists. I still can't
> fathom the difference between @balance and self.balance as mentioned by
you
> (Jan Svitok) above. Does not the self.balance mean the instance variable
> balance of current object? And is not @balance the same thing?

It all starts with the instance variable, @balance. The balance
method is simply a wrapper around it:

   def balance
     @balance
   end

There's no special link between the names; you could also write:

   def my_balance
     @balance
   end

and then do:

   obj.my_balance

It's just a method whose return value happens to be the current value
of an instance variable.

Then there's the other half: the setter-method. Same thing: it's just
a wrapper:

   def balance=(value)
     @balance = value
   end

Again, there's no magic in the naming; you could also do:

   def change_balance_to(value)
     @balance = value
   end

It's customary in such cases, however, to name the get and set methods
with the same name as the instance variable they get and set. In
fact, this idiom:

   def something
     @something
   end

   def something=(value)
     @something = value
   end

is so common, that Ruby gives you a shortcut: instead of writing those
lines of code, you can just do:

   attr_accessor :something

and Ruby will write the methods for you. That's what you've done with
"balance".

One way or another (manually or with an attr method), you have to
define these methods; you can't just say "obj.blah" and expect to get
the value of @blah.

David

Thanks David for a very clear explanation and clearing my doubts. What a

Hi -

···

On Sat, 4 Nov 2006, Learning Ruby wrote:

Thanks David for a very clear explanation and clearing my doubts. What a
coincidence that just the other day I bought and have started reading your
excellent book Ruby for Rails - a must for every Ruby beginner.

Glad to do it!

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org