[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Objects, processes, and encapsulation



Ian,

> If I understood correctly, your point was that a classic object's state 
> is vulnerable to a reflexive invocation (call back). Your example 
> (#2.2.1) merged this problem with exposing the possibility of two objects 
> each containing the other. One of your slides (from memory) captured just 
> the call-back problem...
> 
>   Object1 has a variable 'x' and an interface ("public methods") 'setx', 
>   'getx', and 'foo'. Object2 does setx(42); foo(...); y = getx. You hope
>   y = 42 BUT foo called a method 'bar' in Object3, which then (reflexively)
>   called setx(53).

That's not quite the example used.  I patched in some of my slides to Tom's
talk when presenting it - see slides 14 through 18 in the powerpoint
presentation:

  http://www.cs.ukc.ac.uk/projects/ofa/jcsp/components.ppt

which is linked off the JCSP web page (under JCSP Support Materials,
"Communicating Processes, Components and Scaleable Systems").

The example, however, is Tom's.  The slides illustrate (almost) the same
example as in his paper - namely:

  Object X has a private attribute int (count) and private setCount/getCount
  methods - note they don't have to be public methods.  In some other private
  method, there is code: setCount(42); thing.foo() ... where thing is some
  variable of the method (perhaps passed in as parameter) or some other
  attribute of X (perhaps set externally by a setThing method).  The problem
  is that - after the thing.foo() invocation - we have no locally deducible
  knowledge about the value of count (becuase of callback potential).

The point is that from local inspection of the whole of the class code for
object X, we can't reason about the value of private attributes (even ints)
across external method invocations.  And that's true even if we have the
full source code of the class/interface type for the variable (thing) whose
method is being invoked - because of inheritance/overriding potential.
In effect, all attributes of all objects must be treated as global variables,
even if they are declared private :-( ...

Your example is a bit more complex and doesn't quite show the problem in all
its insanity.  For instance, when Object2 invokes foo() on Object1, that
foo() could simply setx(53) without going via a third party.

> Why occam processes are still vulnerable
> Unless I'm missing something, occam is only really protected by the 
> semantics of ALT, which allows our active object to do just one thing at 
> a time. 

They are still vulnerable to the (more complex) scenario you outlined - as
you described (and also because, as above, Process1 on receiving the foo
channel message can simply change x - without going via Process3).

But it's clear that in that scenario, the value of the set x in Process1
need not be the same when Process2 asks for it later.

For Tom's nasty (for OO) example, we are completely immune in the occam/CSP
world.  As slide 18 is the quoted above powerpoint says, when I write:

  SEQ
    count := 42
    thing ! anything
    ...  what's the value of count now

the answer is 42 - WYSIWYG.  Local analysis is sufficient.  Only this process
can change count (nothing running in parallel can even look at it, even if
they had it in scope) and it hasn't - therefore, it's still 42.

ALTs have nothing to do with it.  The alarm in OO is that when I write:

  count = 42;
  thing.foo ();

where count is a (private) attribute and thing is not an object totally
under my control (i.e. this object created it and has not leaked its
reference), I've no idea any more what value count has any more ...
effectively, count is a global variable and thing.foo() may have changed
it :-( ...

> Better understanding the problem
> Your illustration exposes another weakness in classic OOP - the patent 
> failure to USE encapsulation. So-called "access methods" (get<> and 
> set<>) defeat the aim, which is to hierarchically reduce the degree to 
> which program steps can interact. What's the point of containing 'x' in 
> some object 'y' and then directly manipulating x anyway. The whole idea 
> is that you act only then on 'y'. Objects then just muddy the water.

Exactly!

> When I proposed integrating the (client-server) design rule into a
> programming 
> language at CPA '01, the only objection was that it was too restrictive 
> (and perhaps too prescriptive). Maybe. Then maybe not. I think mostly 
> such concern comes from confusion with data flow. Only cyclic _services_ 
> are banned. Cyclic data flow presents no problem.

But I also want to express I/O-PAR systems.  These also have no problem
with cyclic data-flows, but have no obvious description as client-server.
The point of the design is that all processes are equal peers.  Forcing
their description as client-servers would lead to cyclic services, for
which there are no deadlock guarantess.  Yet they are deadlock-free.

Cheers,

Peter.