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?

  1. 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.

  1. 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 T., 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 C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

Hi –

On Thu, 29 Jan 2009, Tom C. 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.

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.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

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

David A. Black wrote:

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.

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.

environment outside the class. I just can’t see a graceful way to do
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 T. 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 C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

Hi –

On Thu, 29 Jan 2009, Tom C. wrote:

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.

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:

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.rubypal.com
Coming in 2009: The Well-Grounded Rubyist (The Well-Grounded Rubyist)

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

2009/1/29 Tom C. [email protected]:

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.

  1. 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.

  1. 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 T., 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

Robert K. wrote:

was awful. What had been a one line call was now about 14 lines of code.

class is needed, thus setting the instance’s state once, using it with one
http://c2.com/cgi-bin/wiki?CommandPattern

matter, which is way more than I can find anywhere else: "Whenever you’re

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

Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

On Thu, Jan 29, 2009 at 6:03 AM, Tom C. [email protected] wrote:

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

Martin DeMello wrote:

was awful. What had been a one line call was now about 14 lines of code.
projectCollision(x1, y1, z1, vx1, vy1, vz1, x2, y2, z2, vx2, vy2, vz2)
projectCollision(particle1, particle2)
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 C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

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.

Hi –

On Fri, 30 Jan 2009, Tom C. wrote:

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


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

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

Tom C. [email protected] writes:

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

On 31.01.2009 10:02, Tom C. 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.

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

David A. Black wrote:

it" that I’m genuinely wanting to see this matter from the inside

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.

David

Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

Pascal J. Bourguignon wrote:

couldn’t find any explicit guidance anywhere regarding the fundamental

the stable stuff. A Person is something that is table, from her
only in her relations with the surrounding world, then the methods of
are brief).

Pascal,

This is a simply lovely exposition. I’ll add it to the other in this
very helpful thread. And, I’m returning to my code, with these thoughts
in mind, to see what I can learn.

Thanks for taking the time to make these things so clear. Much
appreciated.

Tom

Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

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.

Robert K. wrote:

rageful.
Kind regards

robert

Robert - I absolutely agree, and I can to that (or THOSE)
understanding(s) in my first pass through grad. school. The idea of a
function being a rule that associates two sets of numbers seems to me
the most useful. However, the initial breakthrough for me was to see a
function as a little program - a process: put something in, get
something out. So easy. For some reason, that view it escaped me
throughout high school, etc. (I was a writer, not a calculator!).

Thanks for your thoughts, as always. I always enjoy what you have to
say!

Tom

Tom C., MS MA, LMHC - Private practice Psychotherapist
Bellingham, Washington, U.S.A: (360) 920-1226
<< [email protected] >> (email)
<< TomCloyd.com >> (website)
<< sleightmind.wordpress.com >> (mental health weblog)

On Sat, Jan 31, 2009 at 11:00 PM, Mike S. [email protected]
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.

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

Hi –

On Sun, 1 Feb 2009, Mike S. 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.

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


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

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

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 think you mean: “On the gripping hand…”

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

-Rob

Rob B. http://agileconsultingllc.com
[email protected]

Hi –

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

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


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

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