james_b wrote:
Sean O’Dell wrote:
The method print doesn’t seem to me to belong, logically, to the
string “Hello world”, so I don’t expect the string to know how to
print itself. It does seem to me to belong as a method of $stdout,
however.
There’s a series of articles [0] by Alan Holub about writng UI, based on
the idea that an object should know how to render itself. In it, Holub
claims,
[quote]
I’ll explain the whys and wherefors in a moment, but here are some rules
of thumb that you can apply to see if you’re really looking at an
object-oriented system:
This is, to me, quite insane. =) That puts too much on the shoulders
on the object developer. This assumes that “UI representation” is a
natural function of the object, which it is not. That’s a subjective
parameter that Alan Holub wanted, and completely ignores what others may
want from the object, and that, in my opinion, is the epitome of
breaking object-orientation. =)
- All data is private. Period. (This rule applies to all implementation
details, not just the data.)
I believe I disagree. Dangerous details should be private, yes. But
sometimes data can be exposed when it is protected, because often, a
class variable is itself an object of another class and has its own
protections. If he means raw data, dangerously exposed data, then I agree.
- get and set functions are evil. (They’re just elaborate ways to make
the data public.)
They’re ugly, but if you want to expose potentially dangerous data
elements safely, you have to have these methods, albeit in a more
coder-friendly form (obj.var and obj.var=).
Unless he means actual functions named “get” and “set” for class member
variables. Those do creep me out. Member variable access should be
virtualized somehow.
- Never ask an object for the information you need to do something;
rather, ask the object that has the information to do the work for you.
This is one of those things I was talking about earlier that I also
thought was ludicrous. In a system like this, no object can use the
information from any other object. It’s expected to stand-alone and
perform in a vacuum. Silliness I say, silliness!
- It must be possible to make any change to the way an object is
implemented, no matter how significant that change may be, by modifying
the single class that defines that object.
Well, this turns right around and shows some open-minded thinking, if I
read this right. This sounds somewhat Ruby-esque to me. Every object
should be completely modifiable at run-time.
Not sure if I agree with the “by modifying the single class that defines
it” part though.
I remember back in the early 90’s when I first dove into C++, there
seemed to be this thought process regarding OOP that went something
like: every object should be able to stand alone and interact rarely,
if ever, with anything else because that would break the object’s
encapsulation. I got that feeling from several texts, and I thought
it ludicrous at the time, and still do. As things have evolved, it
seems common sense has stepped in to replace those purist theories,
but that article really took me back to that time.
It’s true there are countless possible messages one could send to a
String object, so having String know about all of them in advance is too
much. (There’s been a similar discussion on ruby-talk regarding math
functions)
I like the Math function organization. I see a fair blend of logic and
practicality in the way they were laid out.
And while the convention in many langauges has been to pass a String
object to an IO object, it may be more appropriate to do it the other
way around, and just call String.print or String.print( someIoObject )
Luckily, it’s dead simple to add this to your code by enhancing the
String class.
class String
def print( io=$stdout )
io.puts( self )
end
end
I’ve been doing this sort of thing in my code, and after a while it
struck me as common sense, not purist theory. I find it goes a long
way towards cleaning up or avoiding procedural code where I want OO, and
I find it easier to read.
It strikes me as purist theory. I tried a lot of this sort of thing,
too and found it was sdrawkcab.
What you have there is a string class that knows how to print itself to
any object which supports a “puts” method. But puts might not be the
right paradigm for other objects that the string could be printed to,
such as a socket or a streaming compression object. You then either
have to switch back to letting the other objects print with the string,
and now you have this mixed code (sometimes the string prints itself,
sometimes other objects handle the work) or you have to add more method
to the string object.
That’s ugly to me. Perhaps not to others, but it is to me.
As Holub states, “I should say that although the foregoing attitude
might sound extreme, my ideas don’t stem from some academic notion of
purity; rather, every time I’ve strayed from the straight and narrow in
my own work, I’ve found myself back in the code fixing it a month or two
later. All of this do-it-wrong-then-go-back-and-fix-it work just started
taking up too much time. It turned out to be easier to just do it right
to begin with. My notions, then, are based on practical experience
gathered while putting together working systems, and a desire to put
those systems together as quickly as possible.”
That’s pretty much how it’s worked for me.
None of the above really strikes me as purist, it strikes me as wishful.
I think Ruby right now is pretty close to the purity I have, over my
12 years of OO-coding, come to believe is how OO should work. Actually,
Ruby has taught a lot of new things; not the least of which is run-time
morphism.
I guess I can explain how I see OOP something like this: the real world
is made up of objects. You can describe OO programming in terms of
real-world examples. I am an object. I am made of other objects. I
interact with other objects. But I move through the world, and do
everything I do, procedurally. I am an object which moves through life
procedurally. I have my job, other objects have theirs. Our places in
the world are clearly defined by “what I am” and “what I do.”
So, in my line of thinking: me.eat(food)
“Hello world”.print to me equates to: food.eat.
I eat. Food doesn’t eat. $stdout prints. Strings don’t print.
Again, this is all just my opinion. I hope I didn’t come across as
insulting; if I did, I apologize in advance!
Sean O'Dell