# Simple class question

**URL:** <https://www.ruby-forum.com/t/simple-class-question/160044>\
**Category:** Ruby\
**Created:** [February 11, 2009, 9:19am UTC](https://www.ruby-forum.com/t/simple-class-question/160044 "2009-02-11T09:19:01Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 9:19am UTC](https://www.ruby-forum.com/t/simple-class-question/160044/1 "2009-02-11T09:19:01Z")

</div>

Tonight I’m exploring the problem of tossing a value at a class instance  
and getting a value back - having it behave like a method, in other  
words. I’ve not looked at this before, and I don’t have much confidence  
about what I’m doing. I have a simple example from Thomas 3rd ed., and  
have modified it a bit. It’s not working as I’d expect - at all.

The code:

=== begin code

# test.rb

def main  
test = Test.new  
puts ‘bye’ # \<=========== line 6  
end

class Test

def t1=(val)  
@val = val  
return 99  
end

def t2=(val)  
@val = val \* 2  
return 99  
end

end

%w(rubygems ruby-debug).each{ |lib| require lib }

Debugger.start  
debugger

main

=== end code

I start this, and the debugger stops it. I put a break point a line 6,  
and continue.  
With execution stopped, I enter at the command line:

(rdb:1) p test.t2 = 2  
2

I should have gotten 4. I only ever get back the same number I put in.  
Can someone tell me what the problem is, and what I have to do to get  
test.t2 to do this simple thing I’m asking of it?

My other question: the “return 99” business is from Thomas. He doesn’t  
explain it. I’ve been reading about “return” and I cannot account for  
why it’s there. It doesn’t seem to do any thing. Can someone explain  
THAT.

Finally, is this general approach I’m taking the best or usual way to  
send data to a class method and get some output? Until now, I thought I  
had to read an accessor variable to get output back, but I’m thinking  
now that that is probably NOT the best way.

What I’m wanting to do, say, create a file object which gives me more  
data when I call upon it (it’ll read a record and do some processing,  
then pass back the results. Normally I’d use a method, but I’m trying to  
become more “classy” in my programming, hence this effort. I’m basically  
still struggling to find a good reason to use a class at all. So far,  
it’s proven far too difficult to get something OUT of a class instance.  
I don’t see the point of the bother, yet. I’m hoping some enlightenment  
will arrive soon.

As always, much thanks for all contributions!

Tom

–

```auto
Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< removed_email_address@domain.invalid >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

```

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 11:04am UTC](https://www.ruby-forum.com/t/simple-class-question/160044/2 "2009-02-11T11:04:17Z")

</div>

2009/2/11 Tom C. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> debugger  
> 2
> 
> I should have gotten 4. I only ever get back the same number I put in. Can  
> someone tell me what the problem is, and what I have to do to get test.t2 to  
> do this simple thing I’m asking of it?

There is no problem - other than probably that you do not yet know  
that = always returns the right hand side no matter what you do in a  
method. This is a safety feature to not allow your expectations to  
fool you when seeing =. You can, however, see that the method works  
as implemented:

irb(main):001:0\> o = Object.new  
=\> #Object:0x7ff9c69c  
irb(main):002:0\> def o.foo=(x) p x; 123 end  
=\> nil  
irb(main):003:0\> o.foo = 300  
300  
=\> 300  
irb(main):004:0\> o.send :foo=, 400  
400  
=\> 123

As you can see, method foo= actually returns 123 as I have told her  
but Ruby never let’s you see it - unless you use #send.

> My other question: the “return 99” business is from Thomas. He doesn’t  
> explain it. I’ve been reading about “return” and I cannot account for why  
> it’s there. It doesn’t seem to do any thing. Can someone explain THAT.

In this case it’s redundant because it’s the last statement in the  
method anyway and a method will return the value of the last  
expression evaluated. In others it’s not:

irb(main):011:0\> def find(enum,x)  
irb(main):012:1\> enum.each {|e| p e; return e if x == e}  
irb(main):013:1\> nil  
irb(main):014:1\> end  
=\> nil  
irb(main):015:0\> find %w{foo bar baz}, “bar”  
“foo”  
“bar”  
=\> “bar”  
irb(main):016:0\> find %w{foo bar baz}, “gogo”  
“foo”  
“bar”  
“baz”  
=\> nil  
irb(main):017:0\>

Here I’m using “return” to terminate the method early.

> Finally, is this general approach I’m taking the best or usual way to send  
> data to a class method and get some output? Until now, I thought I had to  
> read an accessor variable to get output back, but I’m thinking now that that  
> is probably NOT the best way.

It is certainly not for assignments. And in the more general case I  
believe there is a tendency to rather separate these things, i.e.  
setting, getting and performing work. But there is no law which  
prevents methods from returning something useful. In any case you  
should be aware that methods “leak” the value of the last expression  
which can have side effects that you do not intend (i.e. a caller  
stores the value and then later accidentally modifies internal state  
of your object). Having said that you should always care what your  
methods will return - either explicitly or implicitly.

> What I’m wanting to do, say, create a file object which gives me more data  
> when I call upon it (it’ll read a record and do some processing, then pass  
> back the results.

I do not know the nature of your processing but to me it seems  
superior design to separate processing and reading. Take CSV as an  
example: you can iterate the file but do not get back lines (as in the  
case of File) but you get complete records which were parsed from the  
file. You could do something similar, e.g.

class TomsFile  
Record = Struct.new :name, :size, :age

def initialize(io)  
@io = io  
end

def self.open(file)  
File.open(file) do |io|  
tf = TomsFile.new(io)  
begin  
yield tf  
ensure  
tf.cleanup  
end  
end  
end

def each  
@io.each do |line|  
# assuming fields are separated by #  
yield Record.new(\*line.split(/#/))  
end  
end  
end

def cleanup

# NOP for now

end

TomsFile.open “foo.tf” do |tf|  
tf.each do |rec|  
printf “Found %-10s %4d\n”, rec.name, rec.size  
end  
end

You could then add another class, say TomsFileProcessor which gets a  
TomsFile and does the processing like

class TomsFileProcessor  
attr\_reader :count, :sum

def initialize(tf)  
raise ArgumentError unless tf.is\_a? TomsFile  
@tf = tf  
@count = @sum = 0  
end

def process(record)  
@count += 1  
@sum += record.size  
# leakage accepted  
end

def process\_all  
@tf.each {|rec| process(rec)}  
self # rather not accidentally return @tf  
end  
end

And then

TomsFile.open “foo.tf” do |tf|  
tfc = TomsFileProcessor.new tf  
tf.process\_all  
printf “Summary count=%4d sum=%4d\n”, tf.count, tf.sum  
end

(all this untested)

Of course, you could also devise other schemes of interaction.

> Normally I’d use a method, but I’m trying to become more  
> “classy” in my programming, hence this effort. I’m basically still  
> struggling to find a good reason to use a class at all. So far, it’s proven  
> far too difficult to get something OUT of a class instance. I don’t see the  
> point of the bother, yet. I’m hoping some enlightenment will arrive soon.

Hopefully my remarks were helpful…

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 11:38am UTC](https://www.ruby-forum.com/t/simple-class-question/160044/3 "2009-02-11T11:38:56Z")

</div>

Robert K. wrote:

> > === begin code  
> > return 99
> 
> method. This is a safety feature to not allow your expectations to  
> irb(main):004:0\> o.send :foo=, 400
> 
> > 
> 
> irb(main):015:0\> find %w{foo bar baz}, “bar”  
> Here I’m using “return” to terminate the method early.  
> setting, getting and performing work. But there is no law which
> 
> > back the results.
> 
> ```
> tf.cleanup
> 
> ```
> 
> end
> 
> end  
> end  
> (all this untested)
> 
> Hopefully my remarks were helpful…
> 
> Kind regards
> 
> robert

God help me. I had NO idea about this “#send” business. None. Everything  
look different now.

As for your other remarks, I don’t know how to thank you for the labor  
of conveying your teaching to me in such detail. You gave me back a  
great deal for my questions. I qill try to make good use of it. I  
actually AM building a small hash based cyclic graph database with my  
present coding efforts. It’s going quite well, and I have immediate need  
for it, so all this chatter isn’t just programming theory for me. I’d be  
getting work done with it right now if it were completely working.

Thanks again!

Tom

–

```auto
Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< removed_email_address@domain.invalid >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

```

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 11:42am UTC](https://www.ruby-forum.com/t/simple-class-question/160044/4 "2009-02-11T11:42:41Z")

</div>

Tom C. wrote:

> class Test
> 
> def t1=(val)  
> @val = val  
> return 99  
> end
> 
> def t2=(val)  
> @val = val \* 2  
> return 99  
> end
> 
> end

> I enter at the command line:
> 
> (rdb:1) p test.t2 = 2  
> 2
> 
> I should have gotten 4.

I think you should have got 99. You called the method t2=(), and t2=()  
returns 99.

> I only ever get back the same number I put in.  
> Can someone tell me what the problem is, and what I have to do to get  
> test.t2 to do this simple thing I’m asking of it?

The problem appears to be that ruby does not respect a return statement  
in a setter method. Instead, ruby appears to return the value of the  
argument to the setter method–which is not necessarily even the value  
assigned to the instance variable:

class Test

def t1=(val)  
@val = val \* 2  
return 99  
end

def t1  
@val  
end

end

puts t.t1 = 2 #2 (not 99, and not 4!)  
puts t.t1 #4 (as expected)

Normally, a return statement at the end of a method would be the value  
returned to the method call:

class Test

def t1=(val)  
@val = val \* 2  
end  
def t1  
@val  
end

def a  
@val = “goodbye”  
return 99  
end

end

t = Test.new  
puts t.t1 = “hello” #hello (the arg to the setter method)  
puts t.t1 #hellohello (the actual value of @val)  
puts t.a #99 (the return value of the method)  
puts t.t1 #goodbye (as expected)

You can test on your own that ruby does respect a return statement in a  
getter method.

> My other question: the “return 99” business is from Thomas. He doesn’t  
> explain it. I’ve been reading about “return” and I cannot account for  
> why it’s there. It doesn’t seem to do any thing. Can someone explain  
> THAT.

In ruby, a method returns the last expression that was executed in the  
method or what is explicitly specified in a return statement.

> Finally, is this general approach I’m taking the best or usual way to  
> send data to a class method and get some output? Until now, I thought I  
> had to read an accessor variable to get output back, but I’m thinking  
> now that that is probably NOT the best way.

It depends on what you want to do. If you simply want to set and get an  
instance variable’s value, using attr\_accesor saves you from having to  
manually type out the setter and getter methods. However, if you want  
your setter or getter method to transform the value of the argument in  
some way, then you have to define your own getter and setter methods.

> What I’m wanting to do, say, create a file object which gives me more  
> data when I call upon it (it’ll read a record and do some processing,  
> then pass back the results. Normally I’d use a method, but I’m trying to  
> become more “classy” in my programming, hence this effort. I’m basically  
> still struggling to find a good reason to use a class at all. So far,  
> it’s proven far too difficult to get something OUT of a class instance.  
> I don’t see the point of the bother, yet. I’m hoping some enlightenment  
> will arrive soon.

Here is an example of what you can do:

class MyDataProcessor  
attr\_reader :file

def initialize(fname)  
@file = File.open(fname)  
end

def file=(fname)  
@file = File.open(fname)  
end

def get\_data  
data = @file.gets

```
#process data:
data.chomp.split if data #data=nil at EOF

```

end

end

dp = MyDataProcessor.new(“data.txt”)

while data = dp.get\_data  
p data #do something with processed data  
end

dp.file.close

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 11:51am UTC](https://www.ruby-forum.com/t/simple-class-question/160044/5 "2009-02-11T11:51:54Z")

</div>

7stud – wrote:

> > @val = val \* 2  
> > 2  
> > test.t2 to do this simple thing I’m asking of it?  
> > def t1=(val)  
> > puts t.t1 = 2 #2 (not 99, and not 4!)  
> > def t1  
> > t = Test.new  
> > explain it. I’ve been reading about “return” and I cannot account for  
> > Finally, is this general approach I’m taking the best or usual way to  
> > some way, then you have to define your own getter and setter methods.  
> > will arrive soon.

Thanks much for your thoughts. You added some material I didn’t see (or  
haven’t yet understood!) in Robert’s response. I can see you were as  
surprised (more or less) as I was by the failure of the “return n”  
statement to do anything. I never could get it to respond as I had  
expected.

I will study your example. I’m sure it will teach me a few things.  
Thanks!

~t.

–

```auto
Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< removed_email_address@domain.invalid >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

```

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 12:06pm UTC](https://www.ruby-forum.com/t/simple-class-question/160044/6 "2009-02-11T12:06:56Z")

</div>

Tom C. wrote:

> I can see you were as  
> surprised (more or less) as I was by the failure of the “return n”  
> statement to do anything.

I’m a ruby beginner too.

> I will study your example. I’m sure it will teach me a few things.  
> Thanks!

Here is a little fancier get\_data method:

def get\_data  
while data = @file.gets  
yield data.chomp.split  
end

```
@file.close

```

end

A yield statement will send the specified value to a block that you  
specify to the right of the method call:

dp = MyDataProcessor.new(“data.txt”)

dp.get\_data {|processed\_data| p processed\_data}

If you need to execute more than one line of code in that block, then  
you would write it like this:

dp.get\_data do |processed\_data|  
#some code here  
#other code here

p processed\_data  
end

---

<div class="post-metadata">

**Author:** ![tbcox23](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/b9bd4f/32.png) [@tbcox23](https://www.ruby-forum.com/u/tbcox23)\
**Post date:** [February 11, 2009, 3:44pm UTC](https://www.ruby-forum.com/t/simple-class-question/160044/7 "2009-02-11T15:44:49Z")

</div>

Tom C. wrote:

> With execution stopped, I enter at the command line:
> 
> (rdb:1) p test.t2 = 2  
> 2
> 
> I should have gotten 4. I only ever get back the same number I put in.  
> Can someone tell me what the problem is, and what I have to do to get  
> test.t2 to do this simple thing I’m asking of it?

Just to make it clear, although you probably realise by now: you’re not  
calling test.t2, you’re calling test.t2=

The name of the method really does contain the = sign, and is actually  
the symbol :t2=

Operators are other examples of non-alphanumeric method names:

class Test  
def +(other)  
… do something  
end  
def   
…  
end  
def [](key, value)  
…  
end  
end

So you can make your own class look like a Ruby one:

t = Test.new  
puts t + 1 # calls your :+ method  
puts t[123] # calls your :[] method  
t[123] = 456 # calls your :[]= method

I especially like :[] - smiley programming 🙂

Regards,

Brian.
