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

A keyword data type

    Date: Tue, 8 Mar 88 11:06 est
    From: "mike@gold-hill.com after 1-April-88" <mike%acorn%live-oak.lcs.mit.edu@ics.uci.edu>

	Date: Sun, 06 Mar 88 12:08:16 -0800
	From: kipps%etoile.uci.edu@ICS.UCI.EDU
	The comments I've heard so far about keywords lead me to believe that
	there shouldn't be a keyword package at all; instead, there should be a
	keyword data type, i.e., a data type of symbolic literals.  A keyword data
	object always evaluates to itself and has only one user-visible component,
	its print name.

    Frankly, I think this is a great idea. However, there are interactions with
    various features. E.G., &key parameters. For the sake of 
    language extensions like CLOS, the identifiers for &key parameters are
    not really going to be required to be "keywords" at all; rather, they 
    can be any symbol in any package. Use of real "keywords" for this just
    saves making an extra symbol. We would need to change terminology
    so that &key would become &name or &sym or something to avoid confusion.

Such a terminology change might be necessary whether or not keywords
were a distinct data type.  Even without the new data type, the
"keywords" corresponding to &KEY parameters will not be required to be
keywords under the old definition (a symbol in the KEYWORD package).

    A variation of your idea which might capture its value and yet avoid
    turmoil in the CL world would be to make KEYWORD officially a subtype
    of SYMBOL, and to exactly define which symbol operations work on this
    subtype. My suggestion is that SYMBOL-NAME work, but not
    are real symbols, not a subtype, and therefore the issue arises of 
    whether you can IMPORT a keyword, etc.

Actually, I think that SYMBOL should be a subtype of KEYWORD!  Anything
you can do to a keyword you can also do to a symbol, but not vice versa.
Using CLOS syntax (we'll need to get used to this soon):

(defclass keyword ()
	  ((name :initarg name
		 :reader symbol-name)))

;;; This should actually be a shared slot, but I'm not sure how to
;;; access it in the allocate-instance meta-method, because I don't
;;; have Part 3 of the CLOS spec.
(defvar *keyword-table* nil)

(defmethod eval ((object keyword))
  (symbol-value object))

(defmethod symbol-value ((object keyword))

(defmethod initialize-instance :after ((object keyword) &rest ignore)
  (unless (slot-boundp object 'name)
    (error "A name must be specified.")))

(defmethod allocate-instance :around ((class (eql (symbol-class 'keyword)))
				      &key name &allow-other-keys) 
  (or (and (stringp name)
	   (find name *keyword-table* :key #'symbol-name :test #'string-equal))
      (let ((object (call-next-method)))
        (push object *keyword-table*)

(defun intern (string &optional package)
  (if (or (eql package 'keyword)	; back-compatibility
	  (string-equal package "keyword"))
      (make-instance 'keyword :name string)
      (intern-in-package string package)))

(defclass symbol (keyword)
	  ((value :accessor symbol-value
		  :writer set)
	   (function :accessor symbol-function)
	   (plist :initform nil
		  :accessor symbol-plist)
	   (package :initform nil
		    :reader symbol-package)))

(defun symbolp (object)
  (typep object 'symbol))

(defun keywordp (object)
  (and (typep object 'keyword)
       (not (typep object 'symbol))))

I suspect the last function was the reason Mike said keywords should be
subtypes of symbols.  I think the ultimate reason for this backwardness
is that the data types we really need are NAMED-OBJECT, with two
subtypes KEYWORD and SYMBOL.