[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: slot shadowing
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.
Let me describe how these situations are handled in the HP proposal:
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.
The HP proposal behaves pretty much as you suggest. Instances of PORTHOLE
would have two slots named N. One slot is accessible to methods defined on
PORTHOLE, the other is accessible to methods defined on WINDOW.
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.
The HP proposal would not allow a HACKPORT method to access either slot N,
unless methods were provided to do so. The methods to access HACKPORT's N
would be provided by HACKPORT. The methods to access WINDOW's N would be
provided by WINDOW and passed on (inherited) by HACKPORT. If these two sets
of methods have the same names, then HACKPORT would have to provide different
names for the methods it passes on from WINDOW, to avoid a conflict. It would
do this by defining a method GET-WINDOW-N (any name can be used) whose
definition invokes the appropriate method defined by WINDOW (which it refers
to as WINDOW's N). The package system could be used to create different names
for the methods, if desired.
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.
The HP proposal has this behavior.
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."
If VISIBLE-STACK defines an instance variable N, then METHA will access that
N. Otherwise, a reference to N within METHA will access the global variable
N, or get an error if there is no global variable N. As described above, for
METHA to access WINDOW's N or STACK's N, the appropriate methods must be
defined on WINDOW or STACK, and VISIBLE-STACK must declare its desire to
access those variables.
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.
METHA can access WINDOW's N and STACK's N if the appropriate methods are
defined on WINDOW or STACK. These methods can be accessed without conflict as
WINDOW's N and STACK's N within VISIBLE-STACK. They can't both be accessed as
variables, however, because of the name conflict. (The syntax for method
invocation allows qualified names, the syntax for variable reference does
not.) Furthermore, an error will be generated if VISIBLE-STACK attempts to
inherit BOTH methods, as the method names would conflict.