[LISPWORKS][Common Lisp HyperSpec (TM)] [Previous][Up][Next]


Issue CONSTANTP-DEFINITION Writeup

Issue:            CONSTANTP-DEFINITION

References: CONSTANTP (p324)

Related issues: CONSTANTP-ENVIRONMENT

SYMBOL-MACROS-AND-PROCLAIMED-SPECIALS

Category: CLARIFICATION/CHANGE

Edit history: v1, 07 Mar 1991, Sandra Loosemore

v2, 12 Mar 1991, Kent Pitman

v3, 14 Mar 1991, Sandra Loosemore

Problem description:

The specification of CONSTANTP in CLtL says:

CONSTANTP object [Function]

If the predicate CONSTANTP is true of an object, then that object,

when considered as a form to be evaluated, always evaluates to the

same thing; it is a constant. This includes self-evaluating objects

such as numbers, characters, strings, bit-vectors and keywords,

as well as constant symbols declared by DEFCONSTANT, such as

NIL, T, and PI. In addition, a list whose car is QUOTE, such as

(QUOTE FOO), is considered to be constant.

If CONSTANTP is false of an object, then that object, considered

as a form, might or might not always evaluate to the same thing.

Some have interpreted this definition to mean what the first sentence

says, with the rest of the definition being merely an elaboration.

Others have interpreted that the definition seeks to identify a

specific set of things which are considered to be constants for the

purpose of this function, namely

* a self-evaluating object

* a symbol naming a defined constant (built-in or declared by DEFCONSTANT)

* a list whose car is the symbol QUOTE

Most implementors have implemented tests only for these specific items

although there is little first-hand evidence about whether this was

because they felt restricted from implementing other cases or whether

they just didn't have the ambition to think up or implement additional

cases. At least one implementor has implemented a small number of

additional cases.

Some users have assumed that this was an exhaustive list of the

situations for which CONSTANTP must return true, and have written code

which purports to depend on that fact.

Some users have assumed that this was not an exhaustive list of the

situations for which CONSTANTP must return true, and have written code

which would perform better if other kinds of constant forms were

detectable as well.

Of the two authors of this proposal, neither Pitman nor Loosemore

believes there is an ambiguity, but their opinions diverge. And since

users and implementors have in good faith interpreted this wording

differently, then by definition there must be an ambiguity.

Terminology:

For the purposes of this discussion, a `simple constant form' will

be defined as the union of these three items:

* a self-evaluating object

* a symbol naming a defined constant (built-in or declared by DEFCONSTANT)

* a list whose car is the symbol QUOTE

Background:

The description of CONSTANTP in the draft standard (version 8.81)

contained a bug because it did not acknowledge that (QUOTE xxx) would

reliably be detected as a constant by CONSTANTP. The amended text of

the definition, which is the current definition in the draft

specification at the time this proposal is written, says:

CONSTANTP object [Function]

Returns <true> if its argument can be determined by the

<implementation> to be a <constant form>; otherwise,

it returns <false>.

The following items are considered constant forms:

* <constant objects> (such as <numbers>, <characters>, and

the various kinds of <arrays>) are always considered

<constant forms>.

* <constant variables>, such as <keywords>, symbols defined

by Common Lisp as constant (such as NIL, T, and PI),

and symbols defined by the user as constant using DEFCONSTANT

are always considered <constant forms>.

* QUOTE <forms> are considered <constant forms>.

* an <implementation> is permitted to, but not required to,

detect additional <constant forms>. Examples of such forms

that might be detected are: (SQRT PI), (+ 3 2),

(LENGTH '(A B C)), and (LET ((X 7)) (ZEROP X)).

The glossary definition of <constant form> says:

constant form n. any <form> for which <evaluation>

always <yields> the same <value> and which neither

affects nor is affected by the <environment> in which

it is <evaluated>.

[Loosemore has criticized this definition as being overly vague on the

issue of whether a <constant form> may affect or be affected by

the objects accessible in that environment. Pitman says this is

just an oversight.]

At issue is both whether these descriptions accurately capture the

intent of CLtL, and whether even if they do, the definition should

be amended.

Proposal (CONSTANTP-DEFINITION:EXACT):

Clarify that CONSTANTP returns true if and only if its argument is

a `simple constant form' (see definition above).

Rationale:

CONSTANTP is typically used to implement some simple kinds of

code motion optimizations and side-effects analysis, for example

in computing the expansion of a macro or compiler-macro. Permitting

CONSTANTP to return false for the three situations listed would

inhibit these kinds of optimizations in the obvious situations

where they were intended to be applied. Permitting CONSTANTP to

return true in other situations could cause these applications to

perform semantically invalid "optimizations".

There is also a compatibility problem if CONSTANTP is permitted to

be sensitive to the lexical environment in which the form appears

(see the cost to users section below).

Proposal (CONSTANTP-DEFINITION:INTENTIONAL):

1. Clarify that if the predicate CONSTANTP is true of an object,

then that object, when considered as a form to be evaluated,

is a <constant form>.

2. Clarify that if CONSTANTP is false of an object, then that

object, considered as a form, might or might not be a

<constant form>.

3. a. Clarify that the other text in CLtL's definition of CONSTANTP

is intended only as examples and to outline a minimal level

of expectation for users. Explicitly permit implementations

of CONSTANTP to return true for additional situations not listed

among those examples, but which satisfy (1).

b. Clarify that among the actions which an implementation is

permitted to take is to macro expand and to do function

inlining, but not to do expansion of compiler macros.

4. a. Clarify that execution of a <constant form> neither affects nor

is affected by the run-time environment, except that it is

sensitive to the presence of DEFCONSTANT.

b. Clarify that execution of a <constant form> neither affects nor

is affected by either the state of any object except those objects

which are otherwise inaccessible parts of objects created by the

form itself.

That is, a form for which CONSTANTP previously returned NIL

might at some point return T, but not vice versa.

Rationale:

Paragraphs (1) and (2) of this proposal are taken word-for-word

from CLtL (with the appropriate substitution to the new glossary

term) and Pitman thinks they speak for themselves.

Proposal (CONSTANTP-DEFINITION:ADD-ARGUMENT):

Add an optional SIMPLE-P argument to CONSTANTP, which defaults to T.

[Any effect of issue CONSTANT-ENVIRONMENT is assumed to precede the

effect of this issue, so unless the ENVIRONMENT argument proposed

by that issue would precede the SIMPLE-P argument proposed here.]

Define that if the SIMPLE-P argument is true, CONSTANTP

behaves according to proposal EXACT, and that otherwise

it behaves according to proposal INTENTIONAL.

Rationale:

This permits CONSTANTP to satisfy both needs, and allows programmers

to make their intent clear.

Proposal (CONSTANTP-DEFINITION:RENAME):

Rename CONSTANTP to SIMPLE-CONSTANT-FORM-P.

Clarify that SIMPLE-CONSTANT-FORM-P returns true if and only if its argument

is one of the three kinds of things listed in the problem description.

Rationale:

This doesn't preclude an extension named CONSTANTP which does

more work to recognize other kinds of constant forms.

Proposal (CONSTANTP-DEFINITION:EXTEND-SLIGHTLY):

Extend the definition of `simple constant form' to include a fourth case:

(VALUES x1 x2 ... xN)

where every xI is a `simple constant form.'

Test Cases:

These cases are not evaluable forms, but rather objects that are

offered as arguments to the indicated functionality:

#1: 37

True under all proposals. This is self-evaluating and hence

a `simple constant form'.

#2: PI

True under all proposals. This is the name of a defined constant

and hence a `simple constant form'.

#3: 'FOO

True under all proposals. This is a QUOTE form and hence a

`simple constant form.'

#4: (VALUES 37 PI 'FOO)

True under proposals EXACT, INTENTIONAL, ADD-ARGUMENT, and RENAME

iff proposal EXTEND-SLIGHTLY is also adopted. Otherwise, false.

#5: (PROGN NIL)

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

#6: ;after a non-macro/non-inline DEFUN of START-WW-III

(PROGN (START-WW-III) NIL)

False under all proposals.

#7: (SQRT PI)

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

#7: (LET ((X 7)) (ZEROP X))

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

#8: ;after (DEFMACRO FOO () 37)

(FOO)

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

#9: ;in (SYMBOL-MACROLET ((FOO MOST-POSITIVE-FIXNUM)) ...)

FOO

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

#10: (LET ((X (CONS 'X 'Y))) (CDR (RPLACA X 'Z)))

Might be either true or false under proposal INTENTIONAL, or under

proposal ADD-ARGUMENT when the SIMPLE-P argument is true. Otherwise,

must return false.

Current Practice:

Utah Common Lisp, KCL, CMU Common Lisp, Chestnut's Lisp-to-C

translator, and IIM all implement proposal EXACT (and proposal

INTENTIONAL, since it is compatible).

Symbolics Genera implements proposal EXACT+EXTEND-SLIGHTLY

(and proposal INTENTIONAL, since it is compatible), except

that (CONSTANTP ''(#,X)) returns NIL. The implementors indicate

that the intent was to implemention INTENTIONAL and that so far

they've just been busy with other things.

From empirical observation, it appears that Lucid and Allegro also

implement proposal EXACT (and proposal INTENTIONAL, since it is

compatible).

Cost to Implementors:

Very small. Here's a portable definition of CONSTANTP that

conforms with proposal RENAME:

(defun simple-constant-form-p (x &optional env)

(cond ((symbolp x) (eq (variable-information x env) :constant))

((consp x) (eq (car x) 'quote))

(t t)))

Proposal EXTEND-SLIGHTLY modifies that definition in this way:

(defun simple-constant-form-p (x &optional env)

(cond ((symbolp x) (eq (variable-information x env) :constant))

((consp x) (or (eq (car x) 'quote)

(and (eq (car x) 'values)

(every #'simple-constant-form-p (cdr x)))))

(t t)))

Cost to Users:

If there are user programs that depend on CONSTANTP recognizing

either more than just `simple constant forms' OR only

`simple constant forms' they're already nonportable.

The portable uses of CONSTANTP currently include those which depend

on it returning true for `simple constant forms' but which are not

hurt by it returning true for other kinds of constant forms.

Many applications that now use CONSTANTP assume that the value it returns

is not sensitive to the lexical environment in which the form appears.

(Since CONSTANTP has not previously been specified to accept an

environment argument, it is hard to see how any other interpretation

could be made.) Proposals INTENTIONAL and ADD-ARGUMENT represent an

incompatible change in this respect. All calls to CONSTANTP within

user programs would have to be examined to see whether an environment

argument must be passed. This also requires that something other than

EVAL (like FUNCALL of ENCLOSE) be used to compute the value of something

that is CONSTANTP.

Cost of non-adoption:

Users will be confused about what to expect.

Implementors will be confused about what to implement.

The editor will be frustrated by the mess that must be documented.

Performance impact:

For the typical program, the performance impact is not major.

However, it is conceivable that there are cases where recognizing only

`simple constant forms' could have a substantial performance penalty

on certain otherwise-portable uses of DEFINE-COMPILER-MACRO which tried

to base decisions about whether code-motion was appropriate on the return

value of this function, and which found that such code motion was

inhibited by this function being required to return NIL for constant

forms that were not simple constant forms but that the implementation

would have been capable of recognizing as constant. e.g., consider

the following hypothetical example (which doesn't use &environment

only because the status of an environment argument to CONSTANTP is still

a pending issue).

(defun foo (&key x y) (foo-positional x y))

(define-compiler-macro foo (&whole form &rest key-value-pairs)

(cond ((= (length key-value-pairs) 4)

(cond ((and (eq (nth 0 key-value-pairs) :x)

(eq (nth 2 key-value-pairs) :y))

`(foo-positional ,(nth 1 key-value-pairs)

,(nth 3 key-value-pairs)))

((and (eq (nth 0 key-value-pairs) :y)

(eq (nth 2 key-value-pairs) :x)

(or (constantp (nth 1 key-value-pairs))

(constantp (nth 3 key-value-pairs))))

`(foo-positional ,(nth 3 key-value-pairs)

,(nth 1 key-value-pairs)))

(t form)))

...))

Benefits:

The cost of non-adoption is avoided: everyone can finally know

what this function can be depended upon to do.

Esthetics:

Having a well-defined CONSTANTP function is better than having

a vague CONSTANTP function.

Discussion:

Loosemore wrote and supports option EXACT.

Pitman believes that the consensus among the Symbolics developers

is for proposal INTENTIONAL. Regardless of the outcome of the four

`main' proposals, Symbolics would prefer to see option EXTEND-SLIGHTLY

passed.

Loosemore notes:

There is a danger with this issue in trying to make CONSTANTP into

something over-complicated and over-featurized. I don't think that

the original purpose of this function was to do anything more than

perform some quick tests to detect the "obvious" situations, and

trying to extend it into some kind of more sophisticated code-walking

program analysis tool is likely to break more applications than it

would help.

In response to Pitman's urging for more leeway for CONSTANTP to

return true, JonL notes:

Years ago, I suggested a function CONSTANT-EXPRESSION-P which would be

modeled after the similar term in Interlisp; it would try to do the

more complicated-albeit-heuristic processing to notice forms like

(+ 3 (- 9 <symbolic-constant>)). Didn't get a lot of interest then.

Although I think your last example [test case item #10] strains

even our best SSC's, I would still say "Keep it up!"

Barrett raised the issue about expansion of compiler-macros under

proposal INTENTIONAL. Pitman replied:

Sandra talked about the issue of needless extra hair, and I guess this

is where I draw the line. The semantics of the form are fully

specified without compiler macros, and I'd like to keep compiler

macros packaged away in a corner without having them clutter every

single operator. So it seemed simplest to just say they don't get

used by CONSTANTP.


[Starting Points][Contents][Index][Symbols][Glossary][Issues]
Copyright 1996-2005, LispWorks Ltd. All rights reserved.