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

Nesting and the Law



   Redistributed: commonloops.pa
   Date: Thu, 23 Jun 88 07:49:36 EDT
   From: karl lieberherr <lieber@corwin.ccs.northeastern.edu>

   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
proposition.

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.

   -- Karl

				-- John