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.

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

On 11/3/06, Rimantas L. [email protected] wrote:

end
5300.0
Regards,
Rimantas

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?

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

On 11/3/06, Rimantas L. [email protected] wrote:

Regards,
Rimantas

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?

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

On 11/3/06, Learning R. [email protected] wrote:

  self.balance -= amt

def withdraw(amt)

Jon Egil S.

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)

On 11/3/06, Jon Egil S. [email protected] wrote:

  puts balance
raise "You're broke" if balance - amt <= 500

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

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 –

On Fri, 3 Nov 2006, Learning R. wrote:

On 11/3/06, Jon Egil S. [email protected] 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

@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 11/3/06, Jan S. [email protected] wrote:

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 S.) above. Does not the self.balance mean the instance variable
balance of current object? And is not @balance the same thing?

Hi –

On Fri, 3 Nov 2006, Learning R. wrote:

(Jan S.) 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 11/3/06, [email protected] [email protected] wrote:

is that I thought all instance variables of a class are private to
(@balance) or outside (self.balance)
balance of current object? And is not @balance the same thing?
def my_balance
Then there’s the other half: the setter-method. Same thing: it’s just
end
@something = value
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
coincidence that just the other day I bought and have started reading
your
excellent book Ruby for Rails - a must for every Ruby beginner.

Learning R. 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 V.

Hi -

On Sat, 4 Nov 2006, Learning R. 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