values function in Common Lisp

Multiple Values in CL

The language Common lisp
is described in the ANSI standard INCITS 226-1994 (R2004) and has many
implementations.
Each can implement multiple values
as it sees fit, and they are allowed, of course, to cons up a list for them
(in fact, the Emacs Lisp compatibility layer for CL does just
that

but it is, emphatically and intentionally, not a Common Lisp implementation).

Purpose

However, the intent of this facility is to enable passing (at least
some) multiple values without consing (i.e., without allocating
heap memory) and all CL
implementations I know of do that.
In this sense the multiple values facility is an optimization.

Of course, the implementation of this feature can be very different for
different platforms and scenarios. E.g., the first few (say, 20 –
required by the standard
) are
stored in a static of thread-local vector, the next several (1000?) are
allocated on the stack, and the rest (if needed) are allocated on the
heap as a vector or list.

Usage

E.g., the function floor returns two values.
If you write

(setq a (floor 10 3))

you capture only the first one and discard the second one, you need to
write

(setf (values q r) (floor 10 3))

to capture both values. This is similar to what other
languages
might express as

q,r = floor(10,3)

using tuples, except that CL does
not allocate memory to pass (just a few) multiple values, and the
other languages often do.

IOW, one can think of multiple values as an ephemeral struct.

Note that CL can convert multiple values to lists:

(destructuring-bind (q r) (multiple-value-list (floor 10 3))
  ; use q & r here
  ...)

instead of the more efficient and concise

(multiple-value-bind (q r) (floor 10 3)
  ; use q & r here
  ...)

MV & type

CL does not have a special type for the “multiple value object”
exactly because it does not allocate a separate object to pass
around multiple values. In this sense one can, indeed, claim that
values is syntactic sugar.

However, in CL one can declare a
function type returning
multiple values:

(declaim (ftype (real &optional real) (values real real)) floor)

This means that floor returns two values, both
reals (as opposed to returning
a value of type (values real real)), i.e., in this case one might
claim abuse of notation.

Your case

In your specific case, type-of
is an ordinary function (i.e., not a macro or special operator).
You pass it a single object, 1, because, unless you are using
multiple-value-bind and
friends, only the first value is used, so

(type-of (values 1 2 3))

is identical to

(type-of 1)

and type of 1 is bit.

PS: Control return values

One use of values is to
control the return values of a function.
Normally a CL function’s return values are those of the last form.
Sometimes it is not desirable, e.g., the last form return multiple
values and you want your function to return one value (or none,
like void in C):

(defun 2values (x y)
  (floor y x))
(defun 1value (x y)
  (values (floor y x)))
(defun no-values (x)
  (print x)
  (values))

Leave a Comment