lisp-random / locative.lisp

;;;; locative.lisp
;;;; Copyright (c) 2013 Robert Smith


;;;; DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED
;;;;
;;;; Use CL-LOCATIVES instead. It supersedes this.
;;;;
;;;; DEPRECATED DEPRECATED DEPRECATED DEPRECATED DEPRECATED


;;;; This is an example implementation of locatives by using closures
;;;; and GET-SETF-EXPANSION.
;;;;
;;;; Locatives were like C pointers for the lisp machine, but were
;;;; GC-safe. They were also efficiently represented, and specially
;;;; handled.

;;; Example usage:
;;;
;;; CL-USER> (let* ((x (make-array 5 :initial-element 0))
;;;                 (l (locative-for (aref x 2))))
;;;            (setf (dereference l) 5)
;;;            (list l
;;;                  x
;;;                  (dereference l)))
;;;
;;; (#<LOCATIVE {100612B943}> #(0 0 5 0 0) 5)


(defstruct (locative (:predicate locativep)
                     (:constructor %make-locative)
                     (:print-function
                      (lambda (obj stream depth)
                        (declare (ignore depth))
                        (print-unreadable-object (obj stream :type t
                                                             :identity t)))))
  (reader (error "Must provide reader function.") :type function
                                                  :read-only t)
  (writer (error "Must provide writer function.") :type function
                                                  :read-only t))

(defmacro locative-for (place &environment env)
  "Return a locative for PLACE in the environment ENV."
  (multiple-value-bind (vars vals store-vars writer-form reader-form)
     (get-setf-expansion place env)
  `(let* ,(mapcar #'list vars vals)
     (%make-locative :reader (lambda () ,reader-form)
                     :writer (lambda ,store-vars ,writer-form)))))

(defun dereference (locative)
  "Return a value that a locative LOCATIVE points to."
  (funcall (locative-reader locative)))

;;; This DEFSETF is actually incorrect. It is possible that the writer
;;; function can take multiple values. To use the full functionality,
;;; one must simply use LOCATIVE-WRITER.
;;;
;;; FIXME: Use DEFINE-SETF-EXPANDER instead.
(defsetf dereference (locative) (new-val)
  `(funcall (locative-writer ,locative) ,new-val))
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.