[Haskell-cafe] value vs object orientation

Richard A. O'Keefe ok at cs.otago.ac.nz
Tue Oct 14 01:08:09 UTC 2014


There's a half-fun-and-full-earnest proverb:
   It is better to have one data type with 100 functions
   than ten data types with 10 functions each.

I have some guidelines that I wrote up for a class this year:
http://www.cs.otago.ac.nz/cosc326/resources/data.htm.
They were given to students who have been trained in OOP,
and the example is in Java, but my perspective was value
orientation.

One aspect of value orientation that's *not* brought out in
those notes but really should be is that value orientation
goes hand in hand with thinking of the values as elements of
some *ALGEBRA* and a determination that the values and
operations should combine in a way that MAKES SENSE and is
as easy as practical to reason about.

Just today I was looking at a mere 3 pages of OOP code (and
in fact if you threw away the comments and test cases there
was under 1 page of code) which left me completely baffled.
It's basically a zipper, with operations canGoBackward,
canGoForward, goBackward, goForward, and goTo, except that
goTo adds an element, and a dummy element, and backs up
over the dummy element.  But if you add three elements in
succession with goTo, and back up once, you get the 2nd element,
not the 3rd.  Presumably in the original context it *does*
whatever the author wanted, but I can't figure out what it
*means* and certainly would not be able to use it myself.
The thing that has me jumping around shouting and looking for
someone to bite is that the author *knew* what the intended
semantics of the operations was but didn't think it would
matter to his readers...

Let me offer an example from the ANSI Smalltalk standard.
<blockquote>
5.7.8.10 Message: copyReplaceFrom: start to: stop
                       withObject: replacementElement
Synopsis

Answer a new collection conforming to the same protocols as the
receiver, in which the elements of the receiver between start
and stop inclusive have been replaced with replacementElement.

Definition: <sequenceReadableCollection>

This message can be used to insert, append, or replace.
There are three cases:

1. If stop = start - 1, and start is less than or equal to the
size of the receiver, then replacementElement is inserted
between the elements at index stop and start.  None of the
receiver’s elements are replaced.

2. If stop = the size of the receiver and start = stop + 1, then
the operation is an append, and replacementElement is placed at
the end of the new collection.

3. Otherwise, the operation is a replacement, and each of the
receiver’s elements in the given range is replaced by
replacementElement.

The parameters start and stop must be non-negative.
Collections that by definition enforce an ordering on their
elements are permitted to refine this message to reorder
the result.
<snip/>
</blockquote>

Now, as object-oriented definitions go, there's not much
wrong with this.  Cases 1 and 2 are really the same case,
so the description is more complicated than it needs to
be, but that's about it.  You can either replace 1 or more
existing elements with instances of a new one, or insert
exactly 1 element at any position.

From a value perspective, it's clear that there are two
operations here:
   seq copyReplaceFrom: start to: stop withObject: newItem
      -- replace existing elements
   seq copyAdd: newItem beforeIndex: start
      -- insert one new element
They have different validity conditions:
  1 <= start <= stop <= seq size   for the first
  0 <= start - 1 <= seq size       for the second
They have different effects on the size:
  seq size = result size           for the first
  seq size + 1 = result size       for the second
One is idempotent:
  if  seq1 = seq  copyReplaceFrom: a to: z withObject: x
  and seq2 = seq1 copyReplaceFrom: a to: z withObject: x
  (under the first reading), then seq1 = seq2
but the other is not:
  the sizes being different.

Oops.  I just told a lie.  The first reading is NOT idempotent
if the receiver is a collection that keeps its elements in
sorted order.  So it _is_ idempotent for some receivers and it
is _not_ idempotent for others.  Again, the value perspective
would be unhappy with this.

I suppose you could summarise it as
 - the value perspective asks
   "what does this value MEAN?"
   and has as its characteristic activity trying to reason
   about correctness
 - the object perspective asks
   "what does this object DO?"
   and has as its characteristic activity using a debugger.




  


More information about the Haskell-Cafe mailing list