[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

proper use of classes

Tom Cloyd

1/29/2009 12:34:00 AM

Greetings...

I'm continuing my learn-to-write-OO-Ruby journey. Had a recent bad
experience trying to convert a complex method to a class. The method
gets a lot of use in my program, and each time it needs to know a lot
about the environment outside itself. I found myself having to write a
ton of instance variable data into the class instance to get it to do
its job, before I called it each time, then read a few more back out to
get the results. It was awful. What had been a one line call was now
about 14 lines of code. Ack! I gave up and converted it back to a
method, which simply makes more sense. I could not find any
"class-magic" in this experience - just a lot of locked doors.

I now have three questions. I have read a number of people's accounts of
what classes are and how you build them, etc., etc., and no one seems to
address these matters at all well (or else I missed it):

1. HOW do you use a class?

I was assuming that since I couldn't pass data to an instance, after
creation, I have no option but to write data into its instance vars as
needed. Sometimes, it seems there simply is no other option.

But, is it approved practice to do something like

junk = MyClass.new( var_1...var_n ).mymethod

which creates an instance and calls a method which leaves its results in
some instance vars., then simple read the results with...but how?
there's no instance object! (Not that I can find, anyway.) That seems to
leave me only with this possibility:

myclass = MyClass.newMyClass.new( var_1...var_n )
myclass.mymethod
varA = myclass.var_whatever
etc....until I have all my results back out of the instance.

Compared to a simple method call, this seems designed to make me crazy
quickly. Is there a better way?

Then, to call the instance again, I have to write new data into its
instance vars. This simply looks like nonsense, unless one really needs
to have the encapsulation that an instance offers. Am I missing
something? Is this just the facts of life when using classes?

2. Is it accepted practice to simply create a new instance every time
the class is needed, thus setting the instance's state once, using it
with one or more method calls, then moving on to the next new instance?
It occurs to me that maybe Ruby's garbage collection would sweep the old
instance right up, knowing it won't be used again, but I don't know.

My nightmare case is a class which operates on an input record, but
differently each time, depending upon a number of factors in the
environment outside the class. I just can't see a graceful way to do
this. I'm struggling to see why I do OO programming at all in this case.

3. Finally, I'm still struggling with the "when do I make something a
class?" question. I'm surprised that this question is so unimportant or
its answer so obvious that no one much addresses it. Dave Thomas, in his
3rd ed. (I just upgraded, and its really nice!) finally gives two
sentences to the matter, which is way more than I can find anywhere
else: "Whenever you?re designing OO systems, a good first step is to
identify the things you?re dealing with. Typically each type of thing
becomes a class in your final program, and the things themselves are
instances of these classes."(p. 59)

I've been thinking only in terms of functions, things my program does,
and not things it works on or with. Both are relevant, clearly, and I'm
now out on a hunt for "things" that are more than functions. Maybe that
will help.

Anyone have any additional advice about "when to make something a
class?" The principle reasons I see are to achieve scope closure,
persistent state, and object duplication (multiple instances). Did I
miss anything important?

I come to the list with these questions only after days of struggle,
with lots of code, some of it a rather nasty experience (errors I've
never ever seen before!!!). The questions above are the ones I simply
have not been able to resolve, and any help offered will be gratefully
received.

Thanks,

Tom


The easier one (probably):

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


31 Answers

David A. Black

1/29/2009 2:48:00 AM

0

Hi --

On Thu, 29 Jan 2009, Tom Cloyd wrote:

> 1. HOW do you use a class?
>
> I was assuming that since I couldn't pass data to an instance, after
> creation, I have no option but to write data into its instance vars as
> needed. Sometimes, it seems there simply is no other option.

You can pass data to an instance:

instance.some_method(data)

> But, is it approved practice to do something like
>
> junk = MyClass.new( var_1...var_n ).mymethod
>
> which creates an instance and calls a method which leaves its results in some
> instance vars., then simple read the results with...but how? there's no
> instance object!

What you've written here is similar to:

upstring = String.new("David").upcase

or something like that, and it's perfectly legit, though you might
also want to grab the object separately:

string = String.new("David")
upstring = string.upcase

> (Not that I can find, anyway.) That seems to leave me only
> with this possibility:
>
> myclass = MyClass.newMyClass.new( var_1...var_n )

I don't quite get that line. What's newMyClass? (Or maybe it's
garbling again between our machines?)

> myclass.mymethod
> varA = myclass.var_whatever
> etc....until I have all my results back out of the instance.
>
> Compared to a simple method call, this seems designed to make me crazy
> quickly. Is there a better way?

I'm not sure I'm following. I guess the short answer is that there's a
ton of different patterns you can follow, depending on what you need
to do.

> Then, to call the instance again, I have to write new data into its instance
> vars. This simply looks like nonsense, unless one really needs to have the
> encapsulation that an instance offers. Am I missing something? Is this just
> the facts of life when using classes?
>
> 2. Is it accepted practice to simply create a new instance every time the
> class is needed, thus setting the instance's state once, using it with one or
> more method calls, then moving on to the next new instance? It occurs to me
> that maybe Ruby's garbage collection would sweep the old instance right up,
> knowing it won't be used again, but I don't know.
>
> My nightmare case is a class which operates on an input record, but
> differently each time, depending upon a number of factors in the environment
> outside the class. I just can't see a graceful way to do this. I'm struggling
> to see why I do OO programming at all in this case.

Normally you'd write a class in cases where you want more than one of
something. I'm not sure that's the case here. What exactly do you mean
by a class operating on an input record? Or, to go at it a different
way, what exactly is the flow of events that you want to handle? It
may be that you could use a class called InputHandler (or whatever),
and you'd do something like:

ih = InputHandler.new(filename)
fields = ih.parse_into_fields

A class is a generalization. So if what you're doing isn't general,
you may not need or want to model it in classes. If you're writing a
script to parse one particular file, there's quite likely no point
writing a generalized handler class.

I feel like I'm failing to get beyond the rather unhelpful "it
depends" level, but maybe prompt me with some further specifics....


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.r...
Coming in 2009: The Well-Grounded Rubyist (http://manning....)

http://www.wis... => Independent, social wishlist management!

Tom Cloyd

1/29/2009 11:00:00 AM

0

David A. Black wrote:
> Hi --
>
> On Thu, 29 Jan 2009, Tom Cloyd wrote:
>
>> 1. HOW do you use a class?
>>
>> I was assuming that since I couldn't pass data to an instance, after
>> creation, I have no option but to write data into its instance vars
>> as needed. Sometimes, it seems there simply is no other option.
>
> You can pass data to an instance:
>
> instance.some_method(data)
Uh, yes. I had undervalued this possibility, about which I did know. I
suppose I could pass in an array of data describing some external state,
and parse it inside the class. Now, suddenly, I'm seeing a very
economical way to use classes.
>
>> But, is it approved practice to do something like
>>
>> junk = MyClass.new( var_1...var_n ).mymethod
>>
>> which creates an instance and calls a method which leaves its results
>> in some instance vars., then simple read the results with...but how?
>> there's no instance object!
>
> What you've written here is similar to:
>
> upstring = String.new("David").upcase
>
> or something like that, and it's perfectly legit, though you might
> also want to grab the object separately:
>
> string = String.new("David")
> upstring = string.upcase
Yes, I think usually one would.
>
>> (Not that I can find, anyway.) That seems to leave me only with this
>> possibility:
>>
>> myclass = MyClass.newMyClass.new( var_1...var_n )
>
> I don't quite get that line. What's newMyClass? (Or maybe it's
> garbling again between our machines?)
Yeah, it's garble. Don't know why that happened.
>
>> myclass.mymethod
>> varA = myclass.var_whatever
>> etc....until I have all my results back out of the instance.
>>
>> Compared to a simple method call, this seems designed to make me
>> crazy quickly. Is there a better way?
Yeah - stuff the variables into an array, and access the array.
>
> I'm not sure I'm following. I guess the short answer is that there's a
> ton of different patterns you can follow, depending on what you need
> to do.
It's clear to me now that if I can pass in an array of data describing
external state, and can pull it back out by accessing a class instance
variable containing that array, transformed in some way by its having
passed through the class instance. Ah...I'm feeling much better now.
>
>> Then, to call the instance again, I have to write new data into its
>> instance vars. This simply looks like nonsense, unless one really
>> needs to have the encapsulation that an instance offers. Am I missing
>> something? Is this just the facts of life when using classes?
The "nonsense" remains, in that so far I'm just employing a method,
which happens to be formed as a class. There no obvious reason to have
formed it up as a class. Again I wonder - what's the point of using a
class? When do we do it? I can think of some applications, but mostly it
appears that mere methods are fine.
>>
>> 2. Is it accepted practice to simply create a new instance every time
>> the class is needed, thus setting the instance's state once, using it
>> with one or more method calls, then moving on to the next new
>> instance? It occurs to me that maybe Ruby's garbage collection would
>> sweep the old instance right up, knowing it won't be used again, but
>> I don't know.
>>
>> My nightmare case is a class which operates on an input record, but
>> differently each time, depending upon a number of factors in the
>> environment outside the class. I just can't see a graceful way to do
>> this. I'm struggling to see why I do OO programming at all in this case.
>
> Normally you'd write a class in cases where you want more than one of
> something. I'm not sure that's the case here. What exactly do you mean
> by a class operating on an input record? Or, to go at it a different
> way, what exactly is the flow of events that you want to handle? It
> may be that you could use a class called InputHandler (or whatever),
> and you'd do something like:
>
> ih = InputHandler.new(filename)
> fields = ih.parse_into_fields
This looks like a method dressed up as a class. Why do this? I guess it
could make your root program simpler. Every time you want a new record,
you tickle the single class instance you have, and it spits out some
data. But, it quakes like a duck (method), so I have to say that's what
it is, disguised as a class. In the example, as given to this point,
there's no reason for the conversion to a class - none that I can see.
>
> A class is a generalization. So if what you're doing isn't general,
> you may not need or want to model it in classes. If you're writing a
> script to parse one particular file, there's quite likely no point
> writing a generalized handler class.
I have to agree. I reached that conclusion over the weekend, with some
disappointment. I started out some days ago wondering "why classes"? I
got some decent answers back, but have yet to really find an
application. Dave Thomas uses an example of a book story inventory
program, and creates a book class, one instance of which is created for
every book. So where does that leave us, I wonder? With a running
inventory program that has 50,000 little book objects bouncing around
inside? That makes no sense, to me. It certainly is an illustration of
using classes, but to me in no way illustrates the NECESSITY or even the
benefit of doing do. I keep thinking I'm missing something that everyone
else is seeing.

The technology of classes isn't the problem for me. It's the rationale.
I look at some of gems I use, and I see herds of classes. They make some
sense as containers for methods, certainly, but modules could do that,
or some clever naming scheme for set of classes which share some common
domain.

Maybe it's just an organizational thing. A class is way to create a
complex thing that looks and acts simple. That, of course, is a terrific
idea. But, again, mere methods do that quite nicely.

Somehow I'm not quite grasping the heart of the problem I'm having. One
more try - it's clear why sometimes one uses integers and other times
floats. I'm trying to get to that level of clarity regarding classes.
Right now, I appreciate the idea that I might do myClassInstance.a, then
*.b, , and so on, accessing various methods that are conveniently
grouped in my ClassInstance. AND that I might want to subclass this so
as to have a slightly different flavor of it. It's also clear that I
might want to hold the state of some domain, while I go off and do other
things, returning at times to make use of that held state and any
associated methods. It all sounds like a nice idea.

I need to find some part of my code that cries out for this nice
concept, and so far I haven't. So far, I have a class that opens some
files and loads their contents in hashes. Once. And a similar one that
dumps the hashes back out. Once. A method would the job just as well.
Making those classes was just an exercise, it now seems.

I just looked over all my methods, in my current project. They're all
simply blocks of code that get used repeatedly. There's no need to hold
state. All state resides in the main program. Now, THAT - a main program
which manages a database modeled on a graph - I'll turn into a class, as
I might need to have multiple instances running simultaneously, and play
them off each other. THAT, I think, is the first clear need for a class
I've yet seen, in my little coding world. The absolute first.

Well, sorry for the digressive nature of my ruminations. I wander
because I AM a bit lost. Fascinated, but lost. Meanwhile, the code is
coming along nicely, so I can't really complain too much.

Thanks for your thoughts, David- they WERE helpful. If you have any
more, please pass them along. Your comments have always been helpful.

Tom

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


David A. Black

1/29/2009 12:12:00 PM

0

Hi --

On Thu, 29 Jan 2009, Tom Cloyd wrote:

> David A. Black wrote:
>>
>> You wrote:
>>>
>>> My nightmare case is a class which operates on an input record, but
>>> differently each time, depending upon a number of factors in the
>>> environment outside the class. I just can't see a graceful way to do this.
>>> I'm struggling to see why I do OO programming at all in this case.
>>
>> Normally you'd write a class in cases where you want more than one of
>> something. I'm not sure that's the case here. What exactly do you mean
>> by a class operating on an input record? Or, to go at it a different
>> way, what exactly is the flow of events that you want to handle? It
>> may be that you could use a class called InputHandler (or whatever),
>> and you'd do something like:
>>
>> ih = InputHandler.new(filename)
>> fields = ih.parse_into_fields
> This looks like a method dressed up as a class.

"Class" and "method" are not commensurate. They're categorically
different; they don't stand in for each other. What I've got there is
a class, an instance of that class, and an instance method.

> Why do this? I guess it could
> make your root program simpler. Every time you want a new record, you tickle
> the single class instance you have, and it spits out some data. But, it
> quakes like a duck (method), so I have to say that's what it is, disguised as
> a class. In the example, as given to this point, there's no reason for the
> conversion to a class - none that I can see.

It feels to me like you've overthinking the issue. For one thing, it's
important to get back to *objects*. In other words, it's not a tug of
war between classes and methods; it's all about which objects will
help you the most. (Classes are objects, but that's secondary at the
moment.)

In my example, ih is an object that has state (it knows of a filename)
and behavior (it can parse the file into fields, whatever that may
mean). It's possible that I'd need an object that does not have state,
but that can parse files -- in which case, I might write a method on a
class or module (like YAML.load). But if I want my handler to remember
its filename, then a class is not appropriate, because I might have
more than one handler, or some other library that I load might want to
use the handler. The ability to create instances of a class, and
associate each instance with a file, means that the class itself
doesn't have to track who's using which file.

Again, it's really about objects, not classes. If I need three input
handlers, then I want a convenient way to create them. I could do this
each time:

handler = Object.new
handler.extend(SomeHandlerModule)
handler.filename = filename
handler.parse_into_fields

and so on, but a class is a shortcut way of doing something similar.

>> A class is a generalization. So if what you're doing isn't general,
>> you may not need or want to model it in classes. If you're writing a
>> script to parse one particular file, there's quite likely no point
>> writing a generalized handler class.
> I have to agree. I reached that conclusion over the weekend, with some
> disappointment. I started out some days ago wondering "why classes"? I got
> some decent answers back, but have yet to really find an application. Dave
> Thomas uses an example of a book story inventory program, and creates a book
> class, one instance of which is created for every book. So where does that
> leave us, I wonder? With a running inventory program that has 50,000 little
> book objects bouncing around inside? That makes no sense, to me. It certainly
> is an illustration of using classes, but to me in no way illustrates the
> NECESSITY or even the benefit of doing do. I keep thinking I'm missing
> something that everyone else is seeing.
>
> The technology of classes isn't the problem for me. It's the rationale. I
> look at some of gems I use, and I see herds of classes. They make some sense
> as containers for methods, certainly, but modules could do that, or some
> clever naming scheme for set of classes which share some common domain.

You can certainly use modules. The class Class is, in fact, a subclass
of the class Module, which means that in a certain sense, classes are
a specialization of module (basically, a module that can spawn
instances).

> Maybe it's just an organizational thing. A class is way to create a complex
> thing that looks and acts simple. That, of course, is a terrific idea. But,
> again, mere methods do that quite nicely.
>
> Somehow I'm not quite grasping the heart of the problem I'm having. One more
> try - it's clear why sometimes one uses integers and other times floats.

And Integer and Float are both classes :-)

> I'm
> trying to get to that level of clarity regarding classes. Right now, I
> appreciate the idea that I might do myClassInstance.a, then *.b, , and so on,
> accessing various methods that are conveniently grouped in my ClassInstance.
> AND that I might want to subclass this so as to have a slightly different
> flavor of it. It's also clear that I might want to hold the state of some
> domain, while I go off and do other things, returning at times to make use of
> that held state and any associated methods. It all sounds like a nice idea.
>
> I need to find some part of my code that cries out for this nice concept, and
> so far I haven't. So far, I have a class that opens some files and loads
> their contents in hashes. Once. And a similar one that dumps the hashes back
> out. Once. A method would the job just as well. Making those classes was just
> an exercise, it now seems.

Again, class and method are not warring concepts. Even if you write
classes, you still write methods -- and *every* method in Ruby resides
in either a class or a module.

> I just looked over all my methods, in my current project. They're all simply
> blocks of code that get used repeatedly. There's no need to hold state. All
> state resides in the main program. Now, THAT - a main program which manages a
> database modeled on a graph - I'll turn into a class, as I might need to have
> multiple instances running simultaneously, and play them off each other.
> THAT, I think, is the first clear need for a class I've yet seen, in my
> little coding world. The absolute first.

There's absolutely no technical imperative to write classes that you
don't need. It's not a higher plateau of programming; it's just a tool
for spawning objects.

One way to get a sense of how classes are used (and useful) is to
consider the Ruby language itself. In any language, you need to be
able to have multiple filehandles open. In Ruby, that need is
addressed by modeling each filehandle as an instance of File. The
class is, so to speak, the dispatch station, where requests for new
filehandles are fielded. But the class itself does not attach itself
to a particular file, since that would severely limit you.

In my Intro to Ruby training, I've got an exercise where you write a
program modeling a deck of cards. The exercise comes in several
flavors: write a Card class and Deck class, with Deck either
inheriting from Array or not, and write the whole program again
without defining any classes. It's all very valuable, and all the
techniques exposed by the exercise are important. As always, it comes
down to objects, and to what's the best way to launch the objects you
need.


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.r...
Coming in 2009: The Well-Grounded Rubyist (http://manning....)

http://www.wis... => Independent, social wishlist management!

Robert Klemme

1/29/2009 12:30:00 PM

0

2009/1/29 Tom Cloyd <tomcloyd@comcast.net>:
> Greetings...
>
> I'm continuing my learn-to-write-OO-Ruby journey. Had a recent bad
> experience trying to convert a complex method to a class. The method gets a
> lot of use in my program, and each time it needs to know a lot about the
> environment outside itself. I found myself having to write a ton of instance
> variable data into the class instance to get it to do its job, before I
> called it each time, then read a few more back out to get the results. It
> was awful. What had been a one line call was now about 14 lines of code.
> Ack! I gave up and converted it back to a method, which simply makes more
> sense. I could not find any "class-magic" in this experience - just a lot of
> locked doors.
>
> I now have three questions. I have read a number of people's accounts of
> what classes are and how you build them, etc., etc., and no one seems to
> address these matters at all well (or else I missed it):
>
> 1. HOW do you use a class?

You might want to have a look at all those patterns around - they
should give you an idea how to use them. You could start here:
http://c2.com/cgi-bin/wiki?Welco...

> I was assuming that since I couldn't pass data to an instance, after
> creation, I have no option but to write data into its instance vars as
> needed. Sometimes, it seems there simply is no other option.
>
> But, is it approved practice to do something like
>
> junk = MyClass.new( var_1...var_n ).mymethod

That is a rather seldom idiom because usually you want your objects to
live longer. Having said that, there is room for something like that
namely with complex calculations that need a lot of intermediate state
that you want to store in the instance.

> 2. Is it accepted practice to simply create a new instance every time the
> class is needed, thus setting the instance's state once, using it with one
> or more method calls, then moving on to the next new instance? It occurs to
> me that maybe Ruby's garbage collection would sweep the old instance right
> up, knowing it won't be used again, but I don't know.

Yes, that's accepted although one usually tries to keep instances for
longer. In the command pattern you create an instance instead of
invoking a single method:

http://en.wikipedia.org/wiki/Comma...
http://c2.com/cgi-bin/wiki?Comm...

But even in this case the object lives rather long because the
calculation is typically complex and takes more time.

> My nightmare case is a class which operates on an input record, but
> differently each time, depending upon a number of factors in the environment
> outside the class. I just can't see a graceful way to do this. I'm
> struggling to see why I do OO programming at all in this case.

This smells like State or Strategy Pattern.

http://en.wikipedia.org/wiki/Strate...
http://en.wikipedia.org/wiki/Sta...

> 3. Finally, I'm still struggling with the "when do I make something a
> class?" question. I'm surprised that this question is so unimportant or its
> answer so obvious that no one much addresses it. Dave Thomas, in his 3rd ed.
> (I just upgraded, and its really nice!) finally gives two sentences to the
> matter, which is way more than I can find anywhere else: "Whenever you're
> designing OO systems, a good first step is to identify the things you're
> dealing with. Typically each type of thing becomes a class in your final
> program, and the things themselves are instances of these classes."(p. 59)

There are a number of approaches to finding classes. An easy one is
to identify nouns in your description of the problem. Those are
candidate classes and verbs are candidate methods. See the "tutorial"
section for more
http://users.csc.calpoly.edu/~dbutler/tutorials/winte...

> I've been thinking only in terms of functions, things my program does, and
> not things it works on or with. Both are relevant, clearly, and I'm now out
> on a hunt for "things" that are more than functions. Maybe that will help.

Yes, sounds as if this shift in perspective would help you. Rather ask
"what artifacts do I have in my problem domain" instead of "what needs
to be done"?

> Anyone have any additional advice about "when to make something a class?"
> The principle reasons I see are to achieve scope closure, persistent state,
> and object duplication (multiple instances). Did I miss anything important?

I guess with "scope closure" you mean "encapsulation". Persistence is
not mandatory for OO.

I found this book rather inspiring although it might not be the best
introductory text:
http://archive.eiffel.com...

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end

Brian Candler

1/29/2009 1:45:00 PM

0

David A. Black wrote:
> One way to get a sense of how classes are used (and useful) is to
> consider the Ruby language itself. In any language, you need to be
> able to have multiple filehandles open. In Ruby, that need is
> addressed by modeling each filehandle as an instance of File. The
> class is, so to speak, the dispatch station, where requests for new
> filehandles are fielded. But the class itself does not attach itself
> to a particular file, since that would severely limit you.

Good example. Similarly, methods which act on the filesystem, but don't
need to
maintain their own state, are class methods: e.g. File.exist?,
File.rename, File.delete

Another example you could consider is an XML parser. You could write
this as a standalone method in a module:

result = XMLParser.parse(source)

That would parse the source from start to end in one operation. It might
return an object representing the results, or it could yield each
element to a block that you parse. But once the parsing is done, it's
done, and there's no need to remember anything.

One reason you might want to create an *instance* of a parser is to
remember options which will be re-used when parsing multiple documents:

parser = XMLParser.new(:arrays => true, :strip_space => false)
res1 = parser.parse(source1)
res2 = parser.parse(source2)

A completely different reason is so that the parser object can be
attached to a particular document that you are parsing. This would allow
the parsing operation to be spread out over time, and you could ask it
when you like for the next tag - a "pull parser"

parser = XMLParser.new(source)
e1 = parser.next_element
e2 = parser.next_element
...

Here, the object instance keeps a reference to the source object, and
keeps track of the parsing state (e.g. stack of open tags)

So the need to keep state is driven by the user's requirements. If you
don't need to keep state, then don't.

> I've been thinking only in terms of functions, things my program does,
> and not things it works on or with.

There is absolutely nothing wrong with this, and if you follow it to its
conclusion you will end up with functional programming, where every
output is a product of its inputs only. This is how many computer
science courses introduce programming.

For example, if you look at data structures in Erlang, generally you
pass in the old data structure as an argument and receive a new one as a
result:

add_element(Element, Set1) -> Set2

There's no "set object" as such, just some data structure representing a
set, which is passed in and returned.

In Ruby, if you make an object representing a set, the first argument is
implicitly 'self', so there's no need to pass in Set1. Also, your method
may choose to return a new object, or to modify its own state.

Note that whilst you can demonstrate functional programming techniques
with Ruby, the language isn't really geared up to support them fully.
--
Posted via http://www.ruby-....

Tom Cloyd

1/29/2009 9:12:00 PM

0

Robert Klemme wrote:
> 2009/1/29 Tom Cloyd <tomcloyd@comcast.net>:
>
>> Greetings...
>>
>> I'm continuing my learn-to-write-OO-Ruby journey. Had a recent bad
>> experience trying to convert a complex method to a class. The method gets a
>> lot of use in my program, and each time it needs to know a lot about the
>> environment outside itself. I found myself having to write a ton of instance
>> variable data into the class instance to get it to do its job, before I
>> called it each time, then read a few more back out to get the results. It
>> was awful. What had been a one line call was now about 14 lines of code.
>> Ack! I gave up and converted it back to a method, which simply makes more
>> sense. I could not find any "class-magic" in this experience - just a lot of
>> locked doors.
>>
>> I now have three questions. I have read a number of people's accounts of
>> what classes are and how you build them, etc., etc., and no one seems to
>> address these matters at all well (or else I missed it):
>>
>> 1. HOW do you use a class?
>>
>
> You might want to have a look at all those patterns around - they
> should give you an idea how to use them. You could start here:
> http://c2.com/cgi-bin/wiki?Welco...
>
>
>> I was assuming that since I couldn't pass data to an instance, after
>> creation, I have no option but to write data into its instance vars as
>> needed. Sometimes, it seems there simply is no other option.
>>
>> But, is it approved practice to do something like
>>
>> junk = MyClass.new( var_1...var_n ).mymethod
>>
>
> That is a rather seldom idiom because usually you want your objects to
> live longer. Having said that, there is room for something like that
> namely with complex calculations that need a lot of intermediate state
> that you want to store in the instance.
>
>
>> 2. Is it accepted practice to simply create a new instance every time the
>> class is needed, thus setting the instance's state once, using it with one
>> or more method calls, then moving on to the next new instance? It occurs to
>> me that maybe Ruby's garbage collection would sweep the old instance right
>> up, knowing it won't be used again, but I don't know.
>>
>
> Yes, that's accepted although one usually tries to keep instances for
> longer. In the command pattern you create an instance instead of
> invoking a single method:
>
> http://en.wikipedia.org/wiki/Comma...
> http://c2.com/cgi-bin/wiki?Comm...
>
> But even in this case the object lives rather long because the
> calculation is typically complex and takes more time.
>
>
>> My nightmare case is a class which operates on an input record, but
>> differently each time, depending upon a number of factors in the environment
>> outside the class. I just can't see a graceful way to do this. I'm
>> struggling to see why I do OO programming at all in this case.
>>
>
> This smells like State or Strategy Pattern.
>
> http://en.wikipedia.org/wiki/Strate...
> http://en.wikipedia.org/wiki/Sta...
>
>
>> 3. Finally, I'm still struggling with the "when do I make something a
>> class?" question. I'm surprised that this question is so unimportant or its
>> answer so obvious that no one much addresses it. Dave Thomas, in his 3rd ed.
>> (I just upgraded, and its really nice!) finally gives two sentences to the
>> matter, which is way more than I can find anywhere else: "Whenever you're
>> designing OO systems, a good first step is to identify the things you're
>> dealing with. Typically each type of thing becomes a class in your final
>> program, and the things themselves are instances of these classes."(p. 59)
>>
>
> There are a number of approaches to finding classes. An easy one is
> to identify nouns in your description of the problem. Those are
> candidate classes and verbs are candidate methods. See the "tutorial"
> section for more
> http://users.csc.calpoly.edu/~dbutler/tutorials/winte...
>
>
>> I've been thinking only in terms of functions, things my program does, and
>> not things it works on or with. Both are relevant, clearly, and I'm now out
>> on a hunt for "things" that are more than functions. Maybe that will help.
>>
>
> Yes, sounds as if this shift in perspective would help you. Rather ask
> "what artifacts do I have in my problem domain" instead of "what needs
> to be done"?
>
>
>> Anyone have any additional advice about "when to make something a class?"
>> The principle reasons I see are to achieve scope closure, persistent state,
>> and object duplication (multiple instances). Did I miss anything important?
>>
>
> I guess with "scope closure" you mean "encapsulation". Persistence is
> not mandatory for OO.
>
> I found this book rather inspiring although it might not be the best
> introductory text:
> http://archive.eiffel.com...
>
> Kind regards
>
> robert
>
>
David, Brian, Robert - THANKS!

I'm fascinated to read your thoughtful responses, this morning - that,
and gratified. You each responded in different ways, and have offered me
considerable material to think on, and resources to explore. This is
precisely what I was hoping for. I think you "got it" that I'm genuinely
wanting to see this matter from the inside out, and your serious
responses, coupled with my coding adventures, will get the job done, I'm
sure.

My "overthinking" (I've been accused of that before on this list!) is
due to my background in philosophy. To my mind, making sense is the most
important thing we do with our minds, and it often requires a lot of
analytical probing, until all the meaningful dimensions of a problem
space are explored. Only then have you mapped the domain adequately.
That approach has often been my default method, with important things.
Not everyone's style, to be sure, but it is mine.

Again, my sincere gratitude for your taking the time to give me so much.
I will make good use of it!

Tom

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


Martin DeMello

1/29/2009 9:40:00 PM

0

On Thu, Jan 29, 2009 at 6:03 AM, Tom Cloyd <tomcloyd@comcast.net> wrote:
> Greetings...
>
> I'm continuing my learn-to-write-OO-Ruby journey. Had a recent bad
> experience trying to convert a complex method to a class. The method gets a
> lot of use in my program, and each time it needs to know a lot about the
> environment outside itself. I found myself having to write a ton of instance
> variable data into the class instance to get it to do its job, before I
> called it each time, then read a few more back out to get the results. It
> was awful. What had been a one line call was now about 14 lines of code.
> Ack! I gave up and converted it back to a method, which simply makes more
> sense. I could not find any "class-magic" in this experience - just a lot of
> locked doors.

One thing that might help is an object to encapsulate the environment
that is passed to your method. For instance, a method that worked out
whether two particles, given by their initial positions and
velocities, would collide, would look something like

projectCollision(x1, y1, z1, vx1, vy1, vz1, x2, y2, z2, vx2, vy2, vz2)

As a first pass, we'd define a particle class

class Particle
attr_accessor :x, :y, :z, :vx, :vy, :vz
...
end

and call our method with

projectCollision(particle1, particle2)

now particle1 and particle2 are objects of the class Particle, who get
their positions and velocities updated at the appropriate places in
the code. Your methods that deal with updating the particles'
positions and velocities need only pass particle objects around, and
the objects themselves act as slates to track changes to their
internal data. To a first approximation, I've found that using classes
to group and encapsulate function parameters is at least as useful a
refactoring as using classes to hold the functions themselves.

martin

Tom Cloyd

1/29/2009 11:11:00 PM

0

Martin DeMello wrote:
> On Thu, Jan 29, 2009 at 6:03 AM, Tom Cloyd <tomcloyd@comcast.net> wrote:
>
>> Greetings...
>>
>> I'm continuing my learn-to-write-OO-Ruby journey. Had a recent bad
>> experience trying to convert a complex method to a class. The method gets a
>> lot of use in my program, and each time it needs to know a lot about the
>> environment outside itself. I found myself having to write a ton of instance
>> variable data into the class instance to get it to do its job, before I
>> called it each time, then read a few more back out to get the results. It
>> was awful. What had been a one line call was now about 14 lines of code.
>> Ack! I gave up and converted it back to a method, which simply makes more
>> sense. I could not find any "class-magic" in this experience - just a lot of
>> locked doors.
>>
>
> One thing that might help is an object to encapsulate the environment
> that is passed to your method. For instance, a method that worked out
> whether two particles, given by their initial positions and
> velocities, would collide, would look something like
>
> projectCollision(x1, y1, z1, vx1, vy1, vz1, x2, y2, z2, vx2, vy2, vz2)
>
> As a first pass, we'd define a particle class
>
> class Particle
> attr_accessor :x, :y, :z, :vx, :vy, :vz
> ...
> end
>
> and call our method with
>
> projectCollision(particle1, particle2)
>
> now particle1 and particle2 are objects of the class Particle, who get
> their positions and velocities updated at the appropriate places in
> the code. Your methods that deal with updating the particles'
> positions and velocities need only pass particle objects around, and
> the objects themselves act as slates to track changes to their
> internal data. To a first approximation, I've found that using classes
> to group and encapsulate function parameters is at least as useful a
> refactoring as using classes to hold the functions themselves.
>
> martin
>
>
>
Wow. Martin that's a fascinating idea. Terrific notion. Gonna try to
make use of this. But just the idea is great for me to know aout.

Thanks!

Tom

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


David A. Black

1/30/2009 11:43:00 AM

0

Hi --

On Fri, 30 Jan 2009, Tom Cloyd wrote:

> David, Brian, Robert - THANKS!
>
> I'm fascinated to read your thoughtful responses, this morning - that, and
> gratified. You each responded in different ways, and have offered me
> considerable material to think on, and resources to explore. This is
> precisely what I was hoping for. I think you "got it" that I'm genuinely
> wanting to see this matter from the inside out, and your serious responses,
> coupled with my coding adventures, will get the job done, I'm sure.
>
> My "overthinking" (I've been accused of that before on this list!) is due to
> my background in philosophy. To my mind, making sense is the most important
> thing we do with our minds, and it often requires a lot of analytical
> probing, until all the meaningful dimensions of a problem space are explored.
> Only then have you mapped the domain adequately. That approach has often been
> my default method, with important things. Not everyone's style, to be sure,
> but it is mine.

I definitely would not discourage exploration of this kind. I'm 100%
in favor of fully understanding the techniques you're using, and
knowing exactly what Ruby is actually doing. But I still think you're
overthinking it :-)

By that I don't mean that you should stop trying to understand. It's
more that you're multiplying the complexity beyond what it actually
is, for example by positing a kind of substitution relation between
classes and methods.

That said, I think it's true that people learn and grapple with new
things in different ways. I tend to learn in what I think of as the
"Polaroid" style: I start with a breadth-first but very faint
perception of a technology, and gradually the whole picture comes into
view. It's actually kind of weird, because I can know that I'm going
to understand something by the end of the day, and yet not be able to
accelerate the process.

By the same token, I think that what I call "overthinking" is, as you
say, your way of getting there. I just wanted to clarify the point
that I'm not discouraging a deep understanding, just sounding the
buzzer as you cross the invisible line between the road and the
shoulder :-)


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.r...
Coming in 2009: The Well-Grounded Rubyist (http://manning....)

http://www.wis... => Independent, social wishlist management!

Tom Cloyd

1/31/2009 9:03:00 AM

0

David A. Black wrote:
> Hi --
>
> On Fri, 30 Jan 2009, Tom Cloyd wrote:
>
>> David, Brian, Robert - THANKS!
>>
>> I'm fascinated to read your thoughtful responses, this morning -
>> that, and gratified. You each responded in different ways, and have
>> offered me considerable material to think on, and resources to
>> explore. This is precisely what I was hoping for. I think you "got
>> it" that I'm genuinely wanting to see this matter from the inside
>> out, and your serious responses, coupled with my coding adventures,
>> will get the job done, I'm sure.
>>
>> My "overthinking" (I've been accused of that before on this list!) is
>> due to my background in philosophy. To my mind, making sense is the
>> most important thing we do with our minds, and it often requires a
>> lot of analytical probing, until all the meaningful dimensions of a
>> problem space are explored. Only then have you mapped the domain
>> adequately. That approach has often been my default method, with
>> important things. Not everyone's style, to be sure, but it is mine.
>
> I definitely would not discourage exploration of this kind. I'm 100%
> in favor of fully understanding the techniques you're using, and
> knowing exactly what Ruby is actually doing. But I still think you're
> overthinking it :-)
>
> By that I don't mean that you should stop trying to understand. It's
> more that you're multiplying the complexity beyond what it actually
> is, for example by positing a kind of substitution relation between
> classes and methods.
Ah. Now I understand. I actually never positing that at all. I didn't
clarify things when you implied that a while back. Was too busy trying
to keep up with the new material in the developing thread. My problem
was simply that as I was trying to introduce classes into my project
code, I didn't know when I really SHOULD create a class. I had gotten
the impression somewhere that major methods should virtually always be
reconceptualized as classes. I didn't arrive at that notion by thinking.
I'd given up on that, as I didn't have enough material to work with.

But, that perception didn't really make a lot of sense. Still, I
couldn't find any explicit guidance anywhere regarding the fundamental
question I kept asking: WHEN is it the thing to do to make a class? I
did find those two sentences in Thomas (3rd ed) - but that's sparse
pickins, and I didn't find them until AFTER my weekend disaster in which
I spend a pile of time converting a complex method into a class, getting
completely exasperated with the experience, and converting it back. So,
I wasn't overthinking at all. I was mis-perceiving, in the presence of
an absence (ha!) - an absence of clear guidance about the
WHEN-do-classes issue. The best sense I could make of things was that
"big stuff oughta be classes" (bad idea). I didn't yet "get it"
(understatement).
>
> That said, I think it's true that people learn and grapple with new
> things in different ways. I tend to learn in what I think of as the
> "Polaroid" style: I start with a breadth-first but very faint
> perception of a technology, and gradually the whole picture comes into
> view. It's actually kind of weird, because I can know that I'm going
> to understand something by the end of the day, and yet not be able to
> accelerate the process.
This is one of two learning styles that has been documented among
programmers, leading to the realization that programming needs to be
taught simultaneously in two quite different ways - the left-brained
folks need linear progressions and the right-brained folks need
gradually emerging patterns, just as you have described for yourself.
>
> By the same token, I think that what I call "overthinking" is, as you
> say, your way of getting there. I just wanted to clarify the point
> that I'm not discouraging a deep understanding, just sounding the
> buzzer as you cross the invisible line between the road and the
> shoulder :-)
Hey, I can usually use all the warning calls anyone cares to give me,
believe me!

In any case, this thread has been remarkably useful to me, in my
tortured journey toward a more classy (uhem) way of programming.

BTW, I was puzzled for years by the mathematical notion of a function.
It just eluded me. Baffled me. Then, as I was learning to program in
Fortran, years ago, I began to wonder if there was any relation between
Fortran functions (hope you know a little Fortran) and mathematical
functions. Of course, there is. Fortran functions was no problem at all
to grasp, and once I realized they were just another way of expressing a
mathematical function (or perhaps I should say that a math function can
be expressed as a Fortran function, and in fact that was what they were
for), I was seriously rageful. I couldn't understand why something so
easy had been made so hard (for me) in math. classes. I'm still a little
pissed about that. There's little excuse for that kind of stupid teaching.

So, we must attend to our students, and how it is they REALLY learn. I
like to think that we're better at that now than we used to be.

t.
>
>
> David
>


--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Tom Cloyd, MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< tc@tomcloyd.com >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~