License: Public Domain , Load it with Quicklisp: (ql:quickload "its")
Library type: Operator overlay macro , Project complexity: Simple/Medium

its provides convenient access to multiple values of an object in a concise, explicit and efficient way.

its » Examples

(its cons (cons 'foo 'bar))
==
(its (cons t) (cons 'foo 'bar))
==
(its (cons :car :cdr) (cons 'foo 'bar))
==
(let ((my-cons (cons 'foo 'bar)))
  (values (car my-cons) (cdr my-cons)))
=>
foo, bar
(let ((fun (its (cons t))))
  (multiple-value-call #'values
    (funcall fun '(foo . bar))
    (funcall fun '(foo2 . bar2))))
==
(let ((fun (lambda (my-cons)
             (its (cons t) my-cons))))
  (multiple-value-call #'values
    (funcall fun '(foo . bar))
    (funcall fun '(foo2 . bar2))))
==
(multiple-value-call #'values
  (its cons '(foo . bar))
  (its (cons :car :cdr) '(foo2 . bar2)))
==
(their cons '(foo . bar) '(foo2 . bar2))
=>
foo, bar, foo2, bar2
(its (hash-table (gethash 'foo) (gethash 'bar) (gethash 'baz 'no-baz))
  (let ((hash (make-hash-table :test 'eq)))
    (prog1 hash
      (setf (its (hash-table (gethash 'foo) (gethash 'bar)) hash)
            (values 'my-foo 'my-bar)))))
==
(let ((hash (make-hash-table :test 'eq)))
  (setf (gethash 'foo hash) 'my-foo
        (gethash 'bar hash) 'my-bar)
  (values (gethash 'foo hash)
          (gethash 'bar hash)
          (gethash 'baz hash 'no-baz)))
=>
my-foo, my-bar, no-baz
(defclass coords ()
  ((x :initarg :x)
   (y :initarg :y)
   (z :initarg :z)))

(its (t (slot-value 'x 'y)
        (slot-exists-p 'z)
        (slot-boundp 'z))
  (make-instance 'coords :x 0 :y 1))
==
(let ((coords (make-instance 'coords :x 0 :y 1)))
  (values (slot-value coords 'x)
          (slot-value coords 'y)
          (slot-exists-p coords 'z)
          (slot-boundp coords 'z)))
=>
0, 1, t, nil
(defclass coords ()
  ((x :initarg :x :accessor x)
   (y :initarg :y :accessor y)
   (z :initarg :z :accessor z)))

(defsys:define (its coords) (coords)
  (:x () `(x ,coords))
  (:y () `(y ,coords))
  (:z () `(z ,coords))
  (t (:x :y :z)))

(let ((my-coords (make-instance 'coords :x 0 :y 1)))
  (setf (its (coords :z :x) my-coords)
        (values 2 -1))
  (its coords my-coords))
==
(let ((my-coords (make-instance 'coords :x 0 :y 1)))
  (setf (values (z my-coords) (x my-coords))
        (values 2 -1))
  (values (x my-coords) (y my-coords) (z my-coords)))
=>
-1, 1, 2

(let ((my-coords (make-instance 'coords :x 0 :y 4 :z 8)))
  (multiple-value-call #'format nil "At (~A, ~A, ~A)."
                       (its coords my-coords)))
=>
"At (0, 4, 8)."
(their cons '(foo) '(bar) '(baz quux))
==
(let ((function (their cons (3)))) ;efficient
  (funcall function '(foo) '(bar) '(baz quux)))
==
(let ((function (their cons))) ;inefficient
  (funcall function '(foo) '(bar) '(baz quux)))
=>
foo, nil, bar, nil, baz, (quux)
(let ((cons1 (cons 'cons1-car 'cons1-cdr))
      (cons2 (cons 'cons2-car 'cons2-cdr)))
  (setf (their cons cons1 cons2)
        (values 'cons1-new-car 'cons1-new-cdr
                'cons2-new-car 'cons2-new-cdr))
  (values cons1 cons2))
==
(let ((cons1 (cons 'cons1-car 'cons1-cdr))
      (cons2 (cons 'cons2-car 'cons2-cdr)))
  (setf (values (car cons1) (cdr cons1)
                (car cons2) (cdr cons2))
        (values 'cons1-new-car 'cons1-new-cdr
                'cons2-new-car 'cons2-new-cdr))
  (values cons1 cons2))
=>
(cons1-new-car . cons1-new-cdr),
(cons2-new-car . cons2-new-cdr)
;;;Last "t" in object position is evaluated but ignored.
(its (values :lisp-implementation :machine) t)
==
(its (values (:lisp-implementation t) (:machine t)) t)
==
(its (values (:lisp-implementation :type :version)
             (:machine :instance :type :version))
  t)
==
(multiple-value-call #'values
  (its :lisp-implementation t)
  (its :machine t))
==
(multiple-value-call #'values
  (its (:lisp-implementation t) t)
  (its (:machine t) t))
==
(multiple-value-call #'values
  (its (:lisp-implementation :type :version) t)
  (its (:machine :instance :type :version) t))
==
(multiple-value-call #'values
  (values (lisp-implementation-type)
          (lisp-implementation-version))
  (values (machine-instance)
          (machine-type)
          (machine-version)))
=> ;Results may vary. ;P
"SBCL", "1.4.13", "dynamorph", "X86-64",
"Intel(R) Celeron(R) CPU  J1800  @ 2.41GHz"

its » Dictionary

...2 » its

Package its

Description

Simply import its and their for normal usage. Don't (:use)!

This package will be mostly designed for explicit qualification of symbols when it exports more symbols, such as its:expand-specification.

Macro its, (setf its)

specification &optional object

Arguments and Values

  • specification -- A cons or a symbol.
  • object -- An object.

Description

object is required for (setf its).

If object is provided, then object is evaluated first, then specification is evaluated from left to right.

If object is not provided, then a function equivalent to (lambda (object) (its specification object)) is returned.

For now, see the examples for inspiration.

...2 » their

Macro their, (setf their)

specification &body objects

Arguments and Values

  • specification -- A cons or a symbol.
  • objects -- A list.

Description

There must be at least one object for (setf their).

their with one object is exactly equivalent to its with the same arguments.

If at least one object is provided, then objects are evaluated first from left to right, then specification is evaluated from left to right.

If no objects are provided, then a function accepting any number of object arguments is returned. This function returns the concatenation of the results of applying the specification to each of the objects in turn. To avoid expensive runtime concatenation of multiple values, one can (and normally should) provide the number of expected arguments. The function will then accept exactly that many objects. See the relevant example.

...2 » (define its)

Macro (defsys:define (its kind-name))

(&optional object-var) &body clauses => kind

Arguments and Values

  • kind-name -- A symbol.
  • object-var -- A symbol.
  • clauses -- A list.
  • kind -- A kind definition object.

Description

Each clause defines an access specifier for the kind named kind-name, which is created if necessary.

Each clause is of the form (name lambda-list form) or (t (&rest access-specifiers)).

For now, look in definitions.lisp for inspiration.