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

slot shadowing



    Date: 18 Sep 85 18:55 EDT
    From: Dave.Touretzky@A.CS.CMU.EDU

	    Why Automatic Shadowing of Slots Is Essential

		       Dave Touretzky, CMU


    In this note I will try to explain why automatic shadowing of slots is
    essential to a Common Lisp flavor system.  I have read the ObjectLisp
    document distributed at the IJCAI Common Lisp meeting in Los Angeles, which
    I attended, but I am not otherwise familiar with the CommonLoops or HP
    flavors proposals.  I hope people who do understand these proposals will
    respond to the points raised here.

    Example 1:  Customizing a Flavor.  A user of a hairy window system wants to
    create his own flavor of window, called PORTHOLE, which is like an ordinary
    window in most respects.  But PORTHOLE has an instance variable N which the
    user can access and modify.  He defines PORTHOLE as a subtype of WINDOW, and
    writes methods GET-N and SET-N for accessing and setting N.  Unbeknownst to
    him, however, the window system is already using N as the name of a slot.

    Suggested behavior:  instances of PORTHOLE should have two slots named N,
    and one of them, WINDOW's N, should be shadowed for PORTHOLE's methods.
    Let P1 be an instance of PORTHOLE.  Sending P1 a GET-N message should access
    the N the user intended:  PORTHOLE's N.  Sending P1 a CLEAR-SCREEN message
    should access the N inherited from WINDOW, since the CLEAR-SCREEN method is
    itself inherited from WINDOW and the user knows nothing about the shadowing
    of WINDOW's N by his own use of the name.

Packages solve this.

    Example 2:  Replacing a Method.  Suppose a hacker who is familiar with the
    window system wants to create his own type of PORTHOLE, HACKPORT, that uses
    a different CLEAR-SCREEN method.  Since HACKPORT is an instance of PORTHOLE,
    references to N by a HACKPORT method will normally be interpreted as
    references to PORTHOLE's N rather than WINDOW's N.  So we need a way to
    reference the shadowed N in methods defined for PORTHOLE or HACKPORT.  I
    won't suggest a notation for this here.  However, the next example argues
    that we must reference shadowed slots by a point on their inheritance path,
    e.g.  by saying PORTHOLE's N; we can't just say something like SHADOWED-N
    and expect the reference to be resolved.

Packages provide a suitable notation.

    Example 3:  Combining Orthogonal Flavors.  A naive user has available
    to him two predefined flavors, WINDOW and STACK, about whose internals
    he knows nothing.  He wants to build a flavor called VISIBLE-STACK,
    which is a stack whose contents are constantly displayed in a window.
    He defines VISIBLE-STACK as a subtype of both WINDOW and STACK, not
    knowing that both these flavors contain instance variables named N.

    Suggested behavior:  Let S1 be an instance of VISIBLE-STACK.  Sending
    a POP-STACK message to S1 should access STACK's N, while sending a
    SET-FONT message to S1 should access WINDOW's N.  

Packages solve this.

    Problem:  let METHA be a method defined for VISIBLE-STACK.  How should
    references to N be interpreted inside METHA?  If VISIBLE-STACK has its own
    instance variable named N, then this N should shadow both WINDOW's N and
    STACK's N.  But if there is no N defined at the level of VISIBLE-STACK, then
    references to N inside METHA should generate an error message:  "N is an
    ambiguous slot reference."

Packages solve this; a reference to N inside METHA specifies which N it means
explicitly.  Is there a reason why this is inadequate?  Packages already provide
for an error to be signalled if there is an attempt to inherit two symbols with
the same name.

    Problem:  how do we write a new CLEAR-SCREEN method for VISIBLE-STACK?  We
    will need notation to explicitly specify that we want to access the
    shadowed WINDOW's N rather than the shadowed STACK's N.

Packages provide a suitable notation.

    ----------------

    It is obvious what the ObjectLisp solution to this set of problems would
    be:  place each N in a different package to keep the names distinct.  I find
    this highly unsatisfactory.  In the degenerate case, each flavor will end up
    with its own associated package in which instance variables are defined.  A
    user of the ELEPHANT flavor will have to contend with slot names from a
    host of packages, e.g.  ELEPHANT:TRUNK, MAMMAL:HAIR-COLOR,
    VERTEBRATE:SPINE-LENGTH, ANIMAL:HABITAT, LIVING-THING:LIFESPAN, etc.  

I think this is somewhat of a straw man.  Aren't these flavors all part of
the same software module (unlike the earlier examples), and hence all in the
same package and presumed to use non-clashing names?

									  Of
    course the packages could be organized into a hierarchy mimicing the flavor
    hierarchy, so that ELEPHANT:HABITAT would reference ANIMAL:HABITAT unless
    shadowed, but that wouldn't provide for detection of ambiguous slot
    references as required in Example 3 above.  

Packages already provide for an error to be signalled when there is an attempt
to inherit two symbols with the same name.

						Furthermore, unless the
    flavor/package duality was rigidly enforced by the flavor system, the user
    could create quite a mess by hacking the package stuff by hand.

    Finally, if packages are intended to be used for encapsulating separate
    software modules, then we must allow each package to have its own set of
    flavors defined within that package.  Thus, in my hairy robot system, the
    flavor ARM:STACK may describe a stack of blocks, while PLANNER:STACK may be
    an entirely different type of flavor, such as a stack of goals.  If flavors
    usurp the package system for other tasks, like slot shadowing, the original
    purpose of packages -- encapsulation of software modules -- will be hindered.

How are flavors different from software modules?

----------------

I'd like to see counterarguments, but I suspect that they will be of the form
"packages are no good in general" rather than of the form "packages are adequate
for resolving some name clashes, but not for resolving name clashes for
instance variables."