[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Nesting and the Law
- To: email@example.com
- Subject: Nesting and the Law
- From: jrose@Sun.COM (John Rose)
- Date: Mon, 27 Jun 88 11:11:26 PDT
- Cc: commonloops.pa@Xerox.COM
- In-reply-to: karl lieberherr's message of Thu, 23 Jun 88 07:49:36 EDT <8806231149.AA04866@corwin.CCS.Northeastern.EDU>
- Redistributed: commonloops.pa
Date: Thu, 23 Jun 88 07:49:36 EDT
From: karl lieberherr <firstname.lastname@example.org>
Jim Kempf took strong exception to our ideas in writing:
After reading your IEEE Computer article, I must unfortunately
take strong exception to your Law of Demeter for CLOS.
This is a clear statement and requires a clear answer.
We took his message (along with feedback from our students)
as an opportunity to make our Law more clear:
----- LAW OF DEMETER (CLOS, object version, revised) -------------
For all methods M, all function calls inside M must use only the
following objects as method selection arguments:
- M's argument objects or
- slot values of method selection argument classes of M.
(Objects created by the method, or by functions which
it calls, and objects in global variables are viewed as
being passed by arguments.
A method selection argument is an argument which is used
for identifying the applicable methods.)
This law is vacuous, except for the clarification below, because
function calling is the only mode of computation in Lisp,
apart from the evaluation of literal constants and special forms.
(Proof: In Lisp, (F X) == (FUNCALL #'F X), except for special
forms.) Therefore, this Law prohibits nothing. (Or are you
restricting special forms and literals? :-).
The important thing to realize is that Lisp supports, as its
fundamental concept, functional abstraction. Any rule, guideline,
or Law which attempts to differentiate functions according
to their nature or contents is not going to integrate well with Lisp.
The Law of Demeter has implications for the nesting of function
calls. To discuss those implications, we classify functions as follows:
A accessor function returns an object which exists before the
function was called.
A constructor function returns an object which did not exist before
the function was called.
The Law allows the nesting of constructor functions, as well as
the nesting of non-generic functions.
However, the Law prohibits functional composition of generic accessor functions.
Finally! A straightforward statement of your Law. As I expected,
a negative formulation would be clearest.
What this clarifies, perhaps, is a misconception of this Law's proponents
concerning the character of Lisp. In some languages, there are linguistic
distinctions between accessors, constructors, overloaded functions,
and "plain" functions. Checking adherence to your Law requires the
ability to make those distinctions, for every function which appears
in a method body.
In Lisp, such distinctions may be hidden behind functional abstraction
boundaries (e.g., inside a lambda). Therefore, adherence to your Law
not only requires examination of the source code of a method body,
which is reasonable, but also forces the examination of the definitions
of all functions used by the method. That's unreasonable, not least
because it destroys functional abstraction boundaries.
In fact, since Lisp functions can be stored in data structures and
computed at runtime, adherence to your Law is a theoretically undecidable
I don't think your Law integrates well with Lisp. I think it
depends on linguistic distinctions which Lisp happily avoids.
(For the record, I further believe that these distinctions
in a language hamper the creation of good abstractions.)
Here's an alternative law governing slot variables, which preserves
abstraction, instead of destroying it:
The function SLOT-VALUE may only be used to access the
slots of lexically apparent classes.
Clarifications and definitions:
* A class is lexically apparent within its defining
form, and within the body of any method which uses
that class as a selector.
* We define all such locations to be the "scope" of
the class. That is, a class is lexically apparent
within its scope, and nowhere else.
* The call to SLOT-VALUE may appear on the scope of a
class through macroexpansion and DEFCONSTANT
substitution, but not through inline
substitution or runtime use of FUNCALL.
* The slot accessed by any call to SLOT-VALUE must
be determined at compile time. That is, only
literal symbol values and DEFCONSTANT values
may be used as slot names.
* The scope of a class may be extended to include
the scopes of other classes, or to include specific
functions, by the use of a to-be-defined FRIEND
declaration. (This is as in C++, and makes
this rule more flexible without detracting from
a class's autonomy.)
* This rule is made to be broken by debuggers and
other system code.