Generalized Object Modules Design

Les Tyrrell tyrrell at iserve11.lis.uiuc.edu
Tue Mar 5 03:20:08 UTC 2002


Well, I'll try to review the PIE papers again, might even try to grok MOP (
but that would take quite a while- my background is Aerospace, not Comp Sci ).
In the meantime, many of the things you discuss remind me a great deal of what
I've been doing with Oasis ( though to be fair, many things remind me of Oasis
;^).  So, here are my comments:

----- Original Message -----
From: "Alan Kay" <Alan.Kay at squeakland.org>
To: <squeak-dev at lists.squeakfoundation.org>
Sent: Monday, March 04, 2002 8:34 AM
Subject: Re: Generalized Object Modules Design


> To all --
>
> Again, let me draw everyone's attention to the PIE papers of
> Goldstein and Bobrow from PARC ca 1980. One of them -- "A Layered
> Approach to SW Design" (or some such title) -- has some really
> interesting discussions about other approaches to system contexts --
> and this paper (or one of the other ones) shows a browser they
> designed to deal with the different layers, etc. I remember them
> using this browser over the LAN at PARC to allow several different
> programmers in different locations to resolve conflicts
> collaboratively.

> P.S. I don't want to open up a can of worms here, but I think there
> is a deeper way to approach the problems that the current various
> module suggestions -- piggy-backed on a 27 year old architecture on a
> 30 year old language -- are trying to solve.
>       I think a fresher look at identity and meaning plus a
> reinvolvement with message-sending could reveal new insights.
>       For example, for a little while, forget about some of the old
> resuse and space-saving needs from long ago. What we really need to
> know about objects when programming is whether they are truly
> referentially transparent or not -- that is, can they substitute for
> other objects in variables or not? Similarly, from the variable POV,
> are our intentions about variables (with regard to objects they might
> contain) consistent?

Oasis has some fairly deep analytical capabilities in this direction.  I did
this as a means to automatically extract the messages flowing back and forth
between the various objects ( ie, expressions ) in the code.  The intent was
to support a more rapid understanding of large bodies of source code.  Later
on ( or most recently ) I extended this to the point where these fragments (
"shards", in my nomenclature ) are treated as evidence indicating the
existence of "facets", where a facet is a subset of a typical object's
complete interface.  A facet represents a part of an interface which is used
by a particular subset of an object's clients.  At the shard level there is
tremendous evidence that these things ougth to exist, however reaching the
facet level was a fairly hard problem for me for quite a long time.  I do have
a "working" faceting algorithm, hopefully now that I've been through those
hurdles once, other algorithms can be found as well.

FWIW, perhaps facets tend not to be what you may think they are- for instance,
one common pattern I often see is that the interface of a given object is
divided into at least two facets, one which is used by something which "sets
up" the object, ( ie, uses messages like #foo: , #bar: ) while another is then
used by things which "read" the object ( ie, uses messages like #foo and
#bar ).  So, a common split is #( foo: bar: ) and #( foo bar ), not #( foo
foo: ) and #( bar bar: ).  The interesting thing about this is that objects
which set up other objects often do not then use those objects- instead they
give them to something else which uses them.   Not exactly what I was
expecting in OO.  On the other hand, hardly forbidden either.

>       In an object system with polymorphism, this can extend over many
> classes that are deemed substitutes for each other. When we make
> changes, we need to know (a) whether the substitution invariants are
> being perserved or not, and (b) whether the change will force us into
> forking a class or not. One way to use the word "type" is to talk
> about these equivalencies (but I think a new term should be made up
> that isn't burdened with previous meanings).

Again, my background is aero- could you be more specific about what you mean
by "substitution invariants" ?  Is there a particular listing that you have in
mind, or are you talking generally about things such as which messages a given
object is expected to understand, or something else entirely?

Also, what do you mean by being "forced to fork a class"? Do you mean, in
order to preserver behavior expected by existing clients, while simultaneously
supporting new or modified behavior required by new clients?  If so, are you
touching on the various "selector namespace" discussions, or something else?
( FWIW, I do *not* have selector namespacing in Oasis - haven't had time to
deal with that problem.  If anyone cares to forward suggestions for how to do
this in a living, dynamic world I'd be happy to listen ).

>       In an additive system, with type agreement, we can take an
> outside module and freely merge it with the base system. If a class
> from outside is meant to be an improvement in kind of a base class,
> but still has type agreement, then it can replace the base class,
> possibly with some reshaping of existing instances.

As long as the system is fairly inactive, you could do this at the subsystem
level too.  Ie, swap out one core for another, provided that the core has
certain properties ( such as being capable of being properly initiliazed,
which most St cores are *not* ).  "Hot" swapping cores is not something that
I've tried to do yet.  Since I can have any number of "complete" systems in
Oasis at once, it is something that *can* be contemplated, however.

>       It seems to me that most of the nasty problems with modules are
> ones where the new class and its use actually change the meaning of
> the class it overrides, especially when there are extant instances
> that are already in use.

YES!  But again, with selector namespacing this could be handled.  ( why do I
focus on that?  easy- if I had it, then I could allow the clients of existing
instances to see one set of behaviors, while a new set of clients _of the same
instances_ could see a different set of behaviors, selected using the "same"
names.   This is important because those new clients most likely are from a
new module that was added _after_ the "server" instances were already
instantiated. If you want to handle a living, dynamic system then I think you
pretty much need to be able to do this ).  Again, I don't have this, so once
again I'll repeat a plea for anyone in the know to speak up!

An easy make-believe example of this would be a case where you had decided
that all of your modules would from now on require that the result of #add:
should now be the reciever, not the argument, as is commonly the convention
now.  You would want OrderedCollection>>#add: to work in one way for your
modules, but continue to work in the conventional way for client objects
originating in all other modules.  More specifically, you would want instances
of OrderedCollection to behave differently in the methods defined in your
modules than they do in the methods defined in other modules.  That is, to
travel successfully across module boundaries, individual instances must adopt
the customs of the lands they visit.

> Simula 67 had the idea of virtual procedure
> where a method of a subclass would be substituted for a deep method
> in a superclass. Smalltalk provides the opportunity to always do this
> but sending a message to self. There is no mechanism in either of
> these two languages that helps establish whether the overriding
> method has any validity (Simula does protest type conflicts in the
> parameters). Eiffel has some important ideas about constraining
> subclasses to not changes species. Etc. The module problem is a
> superset of virtual procedures. I don't thing any module "solution"
> that doesn't have good strategies to deal with extant instances is
> going to stand up.

Well, strictly speaking is there any mechanism that would assure that _any_
method implementation is valid?  The best that I can think of right now would
be to look at what the clients of a given object are expecting it to do- and
that is what the analytical methods in Oasis are doing.  Howver, in order to
do this one must first have clients- in some cases, notably "frameworks",
clients are remarkably scarce.  Do you have something else in mind?

> This is where new approaches to identity may be required and
> useful.

I think Richard Feynman had a quote ( from his father ) along the lines of
"don't tell me what it _is_, tell me what it _does_".

> For example, there is no question that two Squeaks can
> interoperate via message-passing if they are on two different
> machines or in two different address spaces on the same machine. Here
> are modules in the large. What if we want to have a little more
> control and understanding of when it is appropriate to send a
> particular message (and especially by sending particular objects as
> parameters)? Existing mechanisms don't deal very well with these
> cases in which meaning is what we are trying to determine and compare.

Meaning requires more than knowledge about which messages are being sent-
there are other semantics that looking at selectors will not capture.
Message-eating nils are an interesting thing along those lines- I think Nevin
Pratt suggested this as a way to have nil devour all messages sent to it,
rather than raise exceptions.  In that sense, you have something which
continues to "behave" according to "expectations", all the while lying
gleefully to you about what is being accomplished.  Sort of like Enron.
Expectationallly congruent, but not congruent in the deeper semantics.

>       We could make up a term called "congruence" for some better way
> to establish degrees of equivalence than signatures or interfaces.
> There needs to be more semantics in congruence than the simple
> matching that most systems do now.
>
> What are some good ways to do this?

What do you see that is lacking in seeking things based on "signatures or
interfaces" ?  If we are concerned about messages, and only hold the
_expectation_ rather than the _requirement_ that objects will understand the
messages that we send to them, and likewise for the objects that they answer
in response to those messages, then what is missing from this that would be
needed in order to establish a stronger congruence?  Keep in mind that
signatures/interfaces can, to some extent, be extracted from code
automatically.  Thus, it is not neccessary to declare these in advance and
then conform to them while writing code.  Instead, you can come back to
existing code to see what the analytical tools have to say about what you
_actually_ wrote.

> Cheers,
>
> Alan






More information about the Squeak-dev mailing list