Preferred Instance Variable Access Method

B

Bill Atkins

What's the preferred way of accessing a class's instance variables?
Almost every example I've seen uses the @ form:

class Test
def var_set
@var = 3
end
def var_modify(v)
@vare = 34
return @var
end
end

t = Test.new
t.var_set
puts t.var_modify

The obvious problem with this can be seen in Test#var_modify. The
programmer meant to change the value of @var but made a typo and broke
his code. The program prints 3 instead of 34.

The way around this is through accessors:

class Test
attr_accessor :var
def var_set
self.var = 3
end
def var_modify
self.vare = 34
return self.var
end
end

This produces an error that can be caught.

My question is this: why is this form so rarely used? Is it the extra
typing? Is it somehow un-Rubyesque? It seems like a good way to
catch silly errors like the one above.

Thanks,
Bill
 
D

David A. Black

Hi --

What's the preferred way of accessing a class's instance variables?
Almost every example I've seen uses the @ form:

class Test
def var_set
@var = 3
end
def var_modify(v)
@vare = 34
return @var
end
end

t = Test.new
t.var_set
puts t.var_modify

The obvious problem with this can be seen in Test#var_modify. The
programmer meant to change the value of @var but made a typo and broke
his code. The program prints 3 instead of 34.

The way around this is through accessors:

class Test
attr_accessor :var
def var_set
self.var = 3
end
def var_modify
self.vare = 34
return self.var
end
end

This produces an error that can be caught.

My question is this: why is this form so rarely used? Is it the extra
typing? Is it somehow un-Rubyesque? It seems like a good way to
catch silly errors like the one above.

I'm a little puzzled by your example.... Did you mean var_modify to
take an argument? (It does in your first example, though the argument
isn't used.)

Assuming you do mean "def var_modify(v); self.var=v; end" .... That
is indeed somewhat unidiomatic. From the point of view of the calling
code, it's more idiomatic to do:

obj.var = 100

than

obj.var_modify(100)

In fact it's so Rubyesque that Matz has provided the attr_* family of
method-writing shortcuts :) Wrapping them in further layers of set/get
methods is redundant.

As for the error -- there's no more or less danger here than in many
other places where you use variable names. Consider this:

def blah(x)
y = 1
if x > 5
return y
else
return yy * 2
end
end

Of course yy is a typo, but you'll never know until you call the method
with x <= 5.

That (among other reasons) is why there's so much emphasis placed in the
Ruby community on unit testing.


David
 
J

Jean-Hugues ROBERT

Hi,

At 05:34 08/04/2004 +0900, you wrote:
What's the preferred way of accessing a class's instance variables?

I tend to use @var instead of self.var (I guess var() would work, and
var too).

I see two advantages:
1) Faster (I never benchmarked however)
2) Lines starting with @ are like methods with ! at the end =>
Draw the attention to probable side effect on obj's state.

I do agree that typos can be an issue. There is warning however,
with ruby -w (that sometimes warns for some valid constructions
of mine, I guess defined? could help me avoid that).

Refering to a recent thread, I may add that self.var seems slightly
Python-ish.

I would personally prefer .var but languages with configurable style/
syntax are rare these days (missing C's #define).

Nota: Ruby let you add instance variables on the fly, such variables
default to nil. Maybe some "strict" pragma/hint would be welcome, paving
the way to some optimization where access to instance variables could
be direct versus thru an hash.

FWIW

Jean-Hugues

EOM
 
D

David Alan Black

Hi --

Jean-Hugues ROBERT said:
Hi,

At 05:34 08/04/2004 +0900, you wrote:
What's the preferred way of accessing a class's instance variables?

I tend to use @var instead of self.var (I guess var() would work, and
var too).

I see two advantages:
1) Faster (I never benchmarked however)
2) Lines starting with @ are like methods with ! at the end =>
Draw the attention to probable side effect on obj's state.

Don't forget, though, that these techniques (@var vs. self.var) are
only equivalent in certain simple (and common, but not unique) cases.
If you're doing anything more complex, like:

def var=(x)
@var = x.to_s.upcase
end

then you don't have a choice; you have to go through the method
(self.var = y) rather than just doing @var = y, elsewhere in the
class.

(The original question involved another level of remove (wrapping the
attr_* methods themselves in "var_get" and "var_modify" methods, but
wherever they occur, @var = and self.var= are not automatically
equivalent.)

This also points to a constraint on Eric's point about not wanting to
worry about forgetting the 'self' -- namely, that you can only do that
when you know for sure that #var= is a simple set method for @var.
Also, the @var = y technique could come back to bite you if you
reimplement the setter method and haven't routed your assignments
through it:

attr_accessor :var
def initialize(y)
@var = y # OK until you reimplement #var= to do something
end # non-simple, at which point you have to remember
# that you assigned directly to @var here.

(I would have quoted Eric directly except I'm posting directly to
comp.lang.ruby, because of the gateway problems, and Eric's posts
don't seem to be making it here :-(


David
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top