This has been a great thread.  Lots of interesting concepts have been
argued and many interesting points of view have been shown.  It's
taking me a while to absorb it and I'm nowhere close to being
finished.  I'm attaching to Ryan's post as I found it especially
thought-provoking.

Ryan Pavlik <rpav / mephle.com> writes:
> Actually this isn't a very good example.  This whole argument about
> "print should be a member of an object" is demonstrably inelegant and
> wrong, for a number of reasons (some of which have been noted already):
>
>     *  The action of "printing" presupposes a few things:
>
>        -  A device to print on
>        -  A format in which to print
>        -  Content to print
>
>     *  A String specifies no device on which to print
>
>     *  A String provides content and, to some extent, format
>
>     *  The physical act of printing is device-dependent, and thus in
>        OOP should be encaspulated within the device representation object

One of the tough spots I've bumped into, and which has been touched in
this thread, too, is the difference (sometimes dissonance) between a
model that is easy to understand and a model that is easy to
develop/maintain/extend easily, or in other words an intuitive model
and a good working model.

The former seems to be about how much the model is close to
real world experience and common sense, the latter about how much it
follows certain practices and ways that programming experience has
shown to be effective (i.e. to enable to develop/maintain/extend
easily).

The dissonance lies in the unsurprising fact that an intuitive model
and a good working model don't necessarily coincide.  (Yeah, you are
authorized to think `truism' here. ;-))

Sometimes a very natural model is a very uncomfortable one.  The
example has been pointed out of drawing something on a sheet of paper,
with various combinations and orders of `pen', `paper', `ink',
`figure', and as many suggestions as to who does the `drawing' and
therefore who shall be the receiver of the message and who shall be
the parameter.

What surprised me lies in what was *not* suggested: that it is a
painter who might know how to do the drawing, rather than a pen or a
sheet of paper.  Now allow yourself to be a little surprised as well,
if you will, before reading on. :-)

Thinking from a real world perspective, it would seem only natural
that a painter knew his tools, had access to them and could use them.

Thinking from a programming perspective, though, this smells of
passive data and procedural thinking (which isn't necessarily bad).
Yes, I'm thinking exactly about the memory area that stands for the
sheet of paper and the procedure lighting up some bits here and there
to simulate a trace of ink.

Yet, still thinking from a programming perspective but this time
wearing our Object Oriented Wizard's clothes, it suddenly becomes
natural to think of pen, paper and ink as living and active things.
Wizard says to pen: `Pen, fly to the sheet of paper and draw!' and the
pen does so.  Or, to get back to the string and printing device
example, wizard says to string: `String, lay thyself on the device
surface!' or `Device, receive this string and make it appear on your
surface!'.

Interestingly, much was discussed about the proper combination of pen,
paper, ink and figure, but it seemed somewhat more quietly accepted
that it is a device that does the printing of a string.  The paper was
perceived passive, the device active.

But the device acts no more than the paper, and no more than the pen
or string; it's the painter that moves the pen and draws the figure on
the paper, and it's the device *driver* that moves the virtual pen and
draws the virtual figure on the device's virtual paper.

The `why' of our tendency to consider some things passive and some
things active would lots of thinking in itself.  Who knows, maybe it's
just that, as technology goes on, we're surrounded more and more by
reacting and acting objects, and it makes sense to assign this
property even to those things who were not born with such initiative,
when their representations live somewhere inside the most active of
real objects, the computer. [1]

Or it might just be that, doing so, some things work better, and we're
back to the dissonance between easy to understand vs. good working
systems.  And/or to an unsettling question: `In a world where we speak
to pens and they fly and write, do we really want to stay attached to
models resembling real world?  How many excellent and exciting models
have we chosen to not explore and discover just because they appear so
little natural and real world?'


[1] It was only when re-reading that sentence that I noticed `...those
things *who* were...''

>     *  Undesired coupling: If you store outside data or define outside
>        actions, you will end up in a situation where your methods
>        require outside context which isn't there:
>
>           w  = World.new
>           sp = Sphere.new(w, 0, 0, 5) # Bad coupling, the location and
>                                       # world should not matter here
>
>           :                           # elsewhere
>     
>           sp = Sphere.new(??.., 5)    # We might not have a World here,
>                                       # we just want a sphere
>
>           sp.circumference            # Outside information not relavent
>                                       # to the sphere itself
>
>
>           # Someone else implements it like this:
>
>           w  = World.new
>           sp = Sphere.new(5)
>
>           w.add(sp, 0, 0)             # Good, no coupling
>
>           :
>
>           sp = Sphere.new(5)          # No ties to worry about
>           sp.circumference

This was what most caught my attention, because in the meanwhile I was
working with GTK and teaching AWT on one side (where you do things
like window.add(widget) rather than Widget.new(window)) and was toying
with a little LOGO implementation in C/Ruby (where I had done
something like g = Graphics.new; t = Tortoise.new(g)).

From a real world (sort of) perspective on the model: are coordinates
a property of an object or not?  That's a good question, and I'm
terribly envious the certainty of your answer, Ryan. :-)

Michael Benedikt, architect, wrote about the dimensionality of
Cyberspace [2] and about intrinsic and extrinsic dimensions of
entities in a -- real or perceived -- space.  Intrinsic dimensions are
e.g. color, texture, temperature, etc.  Extrinsic dimensions are x, y,
z.  As an operative definition of extrinsic vs. intrinsic, I assume
that in a moving object extrinsic dimensions change while intrinsic
dimensions stay the same, because ext-rinsic dimensions depend on a
relation with an ext-ernal context.

(Now of course this is limited; intrinsic dimensions are measured on
some scale and once you take that as the external context, you've
turned intrinsic into extrinsic.  But my head is exploding already.)

Now the question: who owns/knows the values of extrinsic dimensions?

Is it the responsibility of the space to know where every sphere it
contains is placed, or is it the responsibility of each sphere to know
where it is, while the space's only job is to contain them?

That's a natural question to hear from a programmer, but then again,
from a real world perspective I don't think it's the right the
question.

Because, of course, it's us observers that realize the relation
between a context and the things it contains.  And coordinates in the
space is precisely a matter of relation among entities, something that
is `in between' the space and the sphere, rather than `of' the space
or `of' the sphere.  Just like the act of drawing is what lies between
a pen and a sheet of paper, not really belonging to either, maybe only
belonging to the painter's mind or hand.  (Attempt at a martial arts
or Japanese oriented joke: Hey, somebody please invent ma-oriented
programming!  :-))

It's this kind of concepts that I find difficult to model in an
object-oriented world, rather than in a procedural world (can I say
observer-oriented world?  Einstein has been insistently knocking
behind my left ear since I've started talking about space and
dimensions. ;-)).

And this leads me to...

The programmer's perspective on the model.  Because in the end we
build programs based not (only) on the rules and concepts that seem
most natural, but on the rules and concepts that work best.

For example: in a CAD we will often want to know the coordinates of
the sphere according to a default coordinate reference (world
coordinates).  When we have this setting:

>           # Someone else implements it like this:
>
>           w  = World.new
>           sp = Sphere.new(5)
>
>           w.add(sp, 0, 0)             # Good, no coupling

How would one get to know the coordinates of sp?  He would have to
travel (iterate) the world along the `contained objects' dimension
looking for the coordinates structure that refers to `sp', maybe
something like:

    coords = world.object_coordinates.find {|id, x, y, z| sp.id == id}

(And note that `id' is kind of an extrinsic dimension related to
another context -- memory -- here held in the object, not in the
context!)

On the other hand, querying `sp' about its coordinates is trivial if
extrinsic dimensions are stored in `sp' itself:

    print sp.x
    print sp.y
    print sp.z

This is more convenient.  But now the sphere is coupled to a specific
context, and we cannot extend the context (for example introducing a
fourth dimension) without making the contained objects aware of it.
Which I suppose is one of the consequences Ryan was getting at.

The sphere also spits out data that are not collected from its own
point of view, instead from that of an external observer, which could
be counted as one more (albeit subtler) break of encapsulation.

[2] _Cyberspace - First Steps_, Massachusetts Institute of Technology,
1991

> These get even worse as you start trying to tie objects and methods with
> less relation together, like String and IO.  Would you consider a
> String#display function that takes a GraphicsDevice?  A GD and
> coordinates? colors? fonts? transformations?  Things get out of hand
> quickly.  What if you're working with multiple interfaces?  String#print
> is an identical concept, except it's merely displaying on an inferior
> rendering device.  And it won't work for ncurses, or without a console.
> Could you use mixin to abstract #print to different devices?  Yes.
> Could you abstract the formatting complexities? Maybe.  Can you
> ensure the concept of printing even makes sense at the target?  No.

Somehow, the content has to arrive on the rendering device.  Somehow,
the device must know additional data about the representation of the
content (I don't say that this additional data `must arrive' because
the rendering device might as well make them up based on its own
reasoning.)

Now, the string is just content.  How does it get to the device?

Since we have accepted that objects can be active when it makes things
work better (ok, *I* have accepted that ;-)), I see nothing wrong
with:

    s = "Hello, world!"
    s.transmit_to(io_device)

....provided that there is some agreed convention that says that
io_devices get content through a well defined interface like:

    class IODevice
      def receive_content(content)
        ...
      end
    end

....so that String#transmit_to knows how to transfer itself to the
IODevice.  The requirement of String to know this interface is the
consequence of making it so intelligent that there must not be an
outside painter or observer that picks the letters up and carries them
to an io_device, thereby knowing both the string and io_device.

What I see something wrong with, and again what I think Ryan was
getting at in the post and in the quote above specifically, is when
string knows more than its content, i.e. knows that additional data
needed for representing a string on a device; data which, yet, is
device-dependent.

So rather than String#display_to or String#print_to, a more balanced
(less prone to abuses or consequences) way to let the string have some
initiative and yet not stomp on others' objects feet could be:

    s = "Hello, World!"
    s.transmit_to(io_device)
    io_device.set_color('blue')
    io_device.set_cursor(100, 70)
    io_device.print_content

Or just:

    s = "Hello, World!"
    s.transmit_to(io_device)

Which reads: IO device listens to the data space and is willing to
display the data that requests it, but at a time and in a way
depending on its policies, not the data's.

So io_device decides whether to automatically assign a presentation to
the content and display it right away, or wait until someone provides
presentation data, or schedule its presentation at regular intervals
in another thread, and so on.  Which, come to think about it, it's
just what could already be happening with SomeObject#display, if the
method name didn't make us assume a communication of content *and* a
subsequent presentation, but just a communication of content.

> Anyhow, this message is getting far too long, so that's all.

I can sense people regretting the same thought didn't come to my mind
sooner. O:-)



Massimiliano