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

Issue: FUNCTION-DEFINITION (Version 1)



Issue:        FUNCTION-DEFINITION
References:   none
Category:     ADDITION
Edit history: 23-Jun-88, Version 1 by Pitman
Status:	      For Internal Discussion

Problem Description:

  There are portable ways to turn symbols and lists into functions,
  but there are no portable ways to get back the original symbols and
  lists given the functions.

Proposal (FUNCTION-DEFINITION:OPTIONAL):

  Introduce a new function called FUNCTION-DEFINITION which took as
  its argument a function and returned three values:
   #1: its ``definition'' as a symbol or list, or NIL if the
       information was no longer available.
   #2: NIL if the definition was enclosed in the null lexical
       environment and something non-NIL if the definition was (or
       might have been) enclosed in some non-null lexical environment.
       [It is always safe for an implementation to return T for this
       value.]
   #3: the `name' of this function. the name is intended for debugging
       only and may be any lisp object -- not necessarily one that would
       be valid for use as a name in DEFUN or FUNCTION, for example.
       By convention, NIL is used to mean that the function had no name.
  Implementations would be free to not record this information, or to provide
  primitives for flushing some or all of the information at any time.

  Examples:
  
    The following examples illustrate some possible return values, but
    are not not intended to be exhaustive:
  
    #1:    (FUNCTION-DEFINITION #'(LAMBDA (X) X))
	or (FUNCTION-DEFINITION (FUNCALL #'(LAMBDA () #'(LAMBDA (X) X))))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), NIL, NIL
  
    #2: (FUNCTION-DEFINITION (FUNCALL #'(LAMBDA () #'(LAMBDA (X) X))))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) NIL), T, NIL
	   but -not- (LAMBDA (X) X), NIL, NIL
  
    #3: (DEFUN FOO (X) X)
	(SETF (SYMBOL-FUNCTION #'BAR) #'FOO)
	(DEFUN FOO (Y) Y)
	(FUNCTION-DEFINITION #'BAR)
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), T, FOO
  
    #4: (DEFUN FOO ()
	  (FLET ((BAR (X) X))
	    #'BAR))
	(FUNCTION-DEFINITION (FOO))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), T, (:INTERNAL FOO 0 BAR)
		  or (LAMBDA (X) X), T, "BAR in FOO"
  
  Rationale:
  
    This functionality would be useful to the pretty printer, debugger,
    inspector, and other tools.
  
  Cost to Implementors:
  
    Because NIL can be returned as a first value, the amount of work forced
    by this proposal is trivial. The following implementation is technically
    legitimate, although many implementations would want to provide something
    more useful:
  
     (DEFUN FUNCTION-DEFINITION (FUNCTION)
       (CHECK-TYPE FUNCTION FUNCTION)
       (VALUES NIL NIL NIL))

Proposal (FUNCTION-DEFINITION:REQUIRED):

  Introduce a new function called FUNCTION-DEFINITION which took as
  its argument a function and returned three values:
   #1: its ``definition'' as a symbol or list, or NIL if the
       information was no longer available.
   #2: NIL if the definition was enclosed in the null lexical
       environment and something non-NIL if the definition was (or
       might have been) enclosed in some non-null lexical environment.
       [It is always safe for an implementation to return T for this
       value.]
   #3: the `name' of this function. the name is intended for debugging
       only and may be any lisp object -- not necessarily one that would
       be valid for use as a name in DEFUN or FUNCTION, for example.
       By convention, NIL is used to mean that the function had no name.
  Implementations would be free to not record this information in file
  compilations. In-core calls to EVAL and COMPILE would be required to
  retain the information, however.

  Examples:
  
    The following examples illustrate some possible return values, but
    are not not intended to be exhaustive:
  
    #1:    (FUNCTION-DEFINITION #'(LAMBDA (X) X))
	or (FUNCTION-DEFINITION (FUNCALL #'(LAMBDA () #'(LAMBDA (X) X))))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), NIL, NIL
	in compiled code.
  
           (FUNCTION-DEFINITION (EVAL '(LAMBDA (X) X)))
	would not be permitted to return NIL, NIL, NIL since the compilation
	occurred in the same environment.

    #2: (FUNCTION-DEFINITION (FUNCALL #'(LAMBDA () #'(LAMBDA (X) X))))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) NIL), T, NIL
	   but -not- (LAMBDA (X) X), NIL, NIL
        in compiled code.
  
	(FUNCTION-DEFINITION (FUNCALL (EVAL '(LAMBDA () #'(LAMBDA (X) X)))))
	would not be permitted to return NIL, NIL, NIL since the compilation
	occurred in the same environment.

    #3: (DEFUN FOO (X) X)
	(SETF (SYMBOL-FUNCTION #'BAR) #'FOO)
	(DEFUN FOO (Y) Y)
	(FUNCTION-DEFINITION #'BAR)
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), T, FOO
        in compiled code.
  
	If the DEFUN had been done interactively, the call to
	FUNCTION-DEFINITION would not be permitted to return NIL, NIL, NIL
	since the compilation occurred in the same environment.

    #4: (DEFUN FOO ()
	  (FLET ((BAR (X) X))
	    #'BAR))
	(FUNCTION-DEFINITION (FOO))
	might return NIL, NIL, NIL
		  or (LAMBDA (X) X), T, NIL
		  or (LAMBDA (X) X), T, (:INTERNAL FOO 0 BAR)
		  or (LAMBDA (X) X), T, "BAR in FOO"
        in compiled code.
  
	If the DEFUN had been done interactively, the call to
	FUNCTION-DEFINITION would not be permitted to return NIL, NIL, NIL
	since the compilation occurred in the same environment.
  
  Rationale:
  
    This functionality would be useful to the pretty printer, debugger,
    inspector, and other tools.
  
    Additionally, this would be useful to programs which need to pass
    around both a function and a representation of a function because a
    single object could be passed which was efficient to call without 
    compromising the ability to reliably retrieve its representation.

  Cost to Implementors:
  
    Because NIL can be returned as a first value, the amount of work forced
    by this proposal is small, but not trivial. A simple implementation
    might allocate a slot in each function that could hold the definition,
    or might allocate a hash table to hold the information.

Current Practice:

  Many implementations record this information, but not all that do
  publish an interface to extracting the information.

  The language T has this operation and calls it DISCLOSE. It is the
  conceptual inverse of the ENCLOSE which occurs in some Scheme dialects,
  and is implemented as what CLOS would call a "generic function".

Cost to Users:

  None. The change is upward compatible.

Cost of Non-Adoption:

  Certain kinds of portable debugging tools would be harder to write.

Benefits:

  The cost of non-adoption would be avoided.

Aesthetics:

  The phrase ``program is data; data is program'' comes up a lot in discussions
  about Lisp. This makes the case for ``program is data'' more interesting.

Discussion:

  Pitman would prefer FUNCTION-DEFINITION:REQUIRED if people would agree to it
  because it is considerably more useful in practice, but would like to see at
  least FUNCTION-DEFINITION:OPTIONAL.