Proper use of classes

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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Hi --

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

···

On Thu, 29 Jan 2009, Tom Cloyd wrote:

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

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

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?WelcomeVisitors

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://c2.com/cgi-bin/wiki?CommandPattern

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.

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/winter96/crc_b/

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:

Kind regards

robert

···

2009/1/29 Tom Cloyd <tomcloyd@comcast.net>:

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

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

···

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.

An attractive aspect of Ruby is how it is usually presented as agnostic
- you can use it in an object oriented style or you can choose
functional or procedural styles. So if you like to think in terms of
procedures instead of objects you can still sit at the same tables as
other Ruby programmers. Having said that, I would guess that any
procedure can be re-represented in terms of objects and your thinking
should move in that direction over time to align with the essence of the
language.

···

--
Posted via http://www.ruby-forum.com/.

David A. Black wrote:

Hi --

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

···

On Thu, 29 Jan 2009, Tom Cloyd wrote:

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Robert Klemme 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.

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?WelcomeVisitors

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:

Command pattern - Wikipedia
http://c2.com/cgi-bin/wiki?CommandPattern

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.

Strategy pattern - Wikipedia
State pattern - Wikipedia

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/winter96/crc_b/

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:
Object-Oriented Software Construction, Second Edition

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

···

2009/1/29 Tom Cloyd <tomcloyd@comcast.net>:

--

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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 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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Hi --

An attractive aspect of Ruby is how it is usually presented as agnostic
- you can use it in an object oriented style or you can choose
functional or procedural styles. So if you like to think in terms of
procedures instead of objects you can still sit at the same tables as
other Ruby programmers. Having said that, I would guess that any
procedure can be re-represented in terms of objects and your thinking
should move in that direction over time to align with the essence of the
language.

I particularly like the way the functional/procedural programming
style is engineered to work with the OO style, in the sense that
functional-style method calls are actually calls to private methods --
and privacy is enforced by having to omit the explicit receiver... so
that methods like puts, which are private methods of Object, can be
called at any point in the program, since self is always an instance
of a descendant of Object.

In some respects, this is perhaps the most productive use of private
methods in Ruby, since the privacy is not strictly enforced. If it did
nothing else than provide a way to integrate the functional style into
the OO architecture, it would still be worth it.

David

···

On Sun, 1 Feb 2009, Mike Stephens wrote:

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

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

The power of Ruby does not come from its object-orientation alone -
how many times do we really use polymorphism or inheritance? Yet I bet
most of us use #select, #map, blocks and literal regular expressions
in almost every program we write. I certainly do.

I personally see Ruby as an elegant melding of Lisp, Smalltalk and
Perl - functional, object-oriented and pragmatic, evenly balanced and
working in harmony.

I recommend every programmer should read
Understanding Object Oriented Programming as an (unintentional)
precautionary tale against the over-zealous application of
object-oriented design,

Regards,
Sean

···

On Sat, Jan 31, 2009 at 11:00 PM, Mike Stephens <rubfor@recitel.net> wrote:

An attractive aspect of Ruby is how it is usually presented as agnostic
- you can use it in an object oriented style or you can choose
functional or procedural styles. So if you like to think in terms of
procedures instead of objects you can still sit at the same tables as
other Ruby programmers. Having said that, I would guess that any
procedure can be re-represented in terms of objects and your thinking
should move in that direction over time to align with the essence of the
language.

Hi --

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 :slight_smile:

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

···

On Thu, 29 Jan 2009, Tom Cloyd wrote:

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

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

Hi --

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 :slight_smile:

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 :slight_smile:

David

···

On Fri, 30 Jan 2009, Tom Cloyd wrote:

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

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

Hi --

An attractive aspect of Ruby is how it is usually presented as agnostic
- you can use it in an object oriented style or you can choose
functional or procedural styles. So if you like to think in terms of
procedures instead of objects you can still sit at the same tables as
other Ruby programmers. Having said that, I would guess that any
procedure can be re-represented in terms of objects and your thinking
should move in that direction over time to align with the essence of the
language.

The power of Ruby does not come from its object-orientation alone -
how many times do we really use polymorphism or inheritance? Yet I bet
most of us use #select, #map, blocks and literal regular expressions
in almost every program we write. I certainly do.

At the same time, though, I'd say that object orientation per se
doesn't depend on polymorphism and inheritance. To me it's the
convergence back onto the sending-msgs-to-objects paradigm that's at
the heart of it (though I don't put that forth as a CS-ly correct
characterization, just my sense of it).

On the third hand... :slight_smile: there's that functional style of calling
methods in Ruby, though it's also OO under the hood of course.

David

···

On Sun, 1 Feb 2009, Sean O'Halpin wrote:

On Sat, Jan 31, 2009 at 11:00 PM, Mike Stephens <rubfor@recitel.net> wrote:

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

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

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-forum.com/\.

David A. Black wrote:

Hi --

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 :slight_smile:

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 :slight_smile:

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.

···

On Fri, 30 Jan 2009, Tom Cloyd wrote:

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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

I think you mean: "On the gripping hand..."

(If you read Larry Niven, that is :wink:

-Rob

Rob Biedenharn http://agileconsultingllc.com
Rob@AgileConsultingLLC.com

···

On Feb 1, 2009, at 6:54 AM, David A. Black wrote:

On the third hand... :slight_smile: there's that functional style of calling
methods in Ruby, though it's also OO under the hood of course.

David

I like to think of Ruby as being the English of programming languages. It's got a large and flexible vocabulary that makes it very powerful to work with, but unlike Perl or Lisp or C it's also a very easy language to get to grips with.

I'm particularly keen on the loose and pragmatic approach to OO. Being able to open classes and objects at will makes it very easy to specialise them for a specific project. And as for inheritance hierarchies, there's much less pressure to build these rigid and gargantuan frameworks than in certain mainstream languages.

As for the functional aspect, I tend to even forget I'm using a functional style because message sending is so pervasive that chaining higher-order functions is the obvious way to solve many problems.

Oh, and best of all Ruby's fun to code in :slight_smile:

Ellie

Eleanor McHugh
Games With Brains
http://slides.games-with-brains.net

···

On 1 Feb 2009, at 11:54, David A. Black wrote:

Hi --
On Sun, 1 Feb 2009, Sean O'Halpin wrote:

On Sat, Jan 31, 2009 at 11:00 PM, Mike Stephens >> <rubfor@recitel.net> wrote:

An attractive aspect of Ruby is how it is usually presented as agnostic
- you can use it in an object oriented style or you can choose
functional or procedural styles. So if you like to think in terms of
procedures instead of objects you can still sit at the same tables as
other Ruby programmers. Having said that, I would guess that any
procedure can be re-represented in terms of objects and your thinking
should move in that direction over time to align with the essence of the
language.

The power of Ruby does not come from its object-orientation alone -
how many times do we really use polymorphism or inheritance? Yet I bet
most of us use #select, #map, blocks and literal regular expressions
in almost every program we write. I certainly do.

At the same time, though, I'd say that object orientation per se
doesn't depend on polymorphism and inheritance. To me it's the
convergence back onto the sending-msgs-to-objects paradigm that's at
the heart of it (though I don't put that forth as a CS-ly correct
characterization, just my sense of it).

----
raise ArgumentError unless @reality.responds_to? :reason

Tom Cloyd <tomcloyd@comcast.net> writes:

[...] 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).

First you write a problem statement.
Then you identify the important words in it.
Nouns will become classes.
Verbs will become methods.
(approximatively).

The idea is that what has nouns in natural language are the objects
that have some stability in the real world, and what has verbs are the
actions.

Of course, you can have reification of the actions or the
associations, when you start to speak about verbs (notice that "verb"
is a noun, not a verb).

    For example, when you write:

    (def m(x)
      (2 * x)
    end)

    you actually instantiate an object of the class Method:

    (Object . method "m")
    --> #<Method: Class(Object)#m>

    but you do that only when you're talking at a meta-level, here it's
    the level of the Ruby language, not that of your problem domain.

Instead of reifying the "big stuff", you should rather try to reify
the _stable_ stuff. A Person is something that is table, from her
birth to her death. On the other hand, eating, sleeping, working,
reproducing, breathing, are temporary actions. There even are actions
that cannot be done during all the life time. For example, a baby
Person has no walk method. This method is programmed during the first
few years.

Objects encapsulate state and methods.

When your problem domain (cf the problem statement) considers a Person
only in her relations with the surrounding world, then the methods of
a Person will be Ruby methods. You won't need to reify these methods.

On the other hand, if your problem statement is to implement a Person
simulator, then it's possible that the methods of a Person need to be
reifed, so you can add, change and remove these methods. Imagine
having to write a Person simulator that starts in the baby state, and
that should evolve a walk method. In this case, you could have a
MotorMethod class, and a Walk subclass, as well as classes such as
Muscle, Bone, Nerve, etc. But these kind of classes would be named in
the problem statement (at least latently, sometimes problem statements
are brief).

···

--
__Pascal Bourguignon__

IMHO there is an important distinction though which makes Fortran functions a bad example: mathematical functions usually do not have side effects, i.e. they can be completely described in terms of input and output. I view them as a relationship (or call it a mapping) which assigns particular output values to particular input values. If I'm not mistaken, a Fortran function can have side effects on arguments (and probably global variables). A closer analogy are functions in - you guessed it - functional languages.

Kind regards

  robert

···

On 31.01.2009 10:02, Tom Cloyd wrote:

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.

Oh, and best of all Ruby's fun to code in :slight_smile:

Right, as long as everyone remembers not to scuff their knees on the
playground sand jumping from the jungle gym :slight_smile:

Todd