Normative Rules: Dialect Portability Warnings
← Prev | ↑ Chapter | Next → | Index | Symbols
Normative Rules: Dialect Portability Warnings
Statement
A dialect portability warning is a diagnostic emitted when a program
uses a construct — a special form, a function, or a particular argument
shape — that is not portable to the host targeted by the currently
selected dialect. The canonical example is the &rest parameter in
defun (chapter 24, "BricsCAD Extensions"): it is native to BricsCAD
(and to clautolisp) but unsupported by AutoCAD, which has no
variable-arity user functions.
These warnings are advisory. They do not alter evaluation: under a
dialect whose target host supports the construct natively, the construct
runs and no warning is produced; under a dialect whose target host
lacks it, the construct still runs in clautolisp (which is a superset)
but a warning is printed. A construct that is portable under the active
dialect never warns. An implementation may additionally offer a knob that
escalates such a warning to an error (compare the :strict-error
diagnostic mode of :unbound-variable-mode, chapter 3); escalation is
optional and non-conforming when it changes whether a program runs.
Behavior versus warning, and the divergence taxonomy
The &rest example above is one of several kinds of portability
warning. This subsection is the normative framework that classifies them
and fixes, for each dialect, what the operation does and whether a
warning accompanies it. Every function entry that documents a
per-vendor difference (its *** clautolisp deviation note) MUST state
which case below it falls into.
Behavior and warning are orthogonal
In a controlled implementation every argument value is accepted: the
function does something — it returns a value, or it performs a
non-local exit (an error, or a normal early exit). The exit may itself
be the caller's expected, meaningful result. "Rejects the value" is
therefore not a category; there is no "out-of-range" input a function
declines to act on. A warning is a separate, advisory portability
diagnostic written to the diagnostic channel (*error-output*); it is
independent of whether the call returns or exits, and it never changes
the value channel (stdout / the return value), so a dialect that
reproduces a vendor stays byte-faithful on the value channel while
clautolisp adds the warning on the side channel.
Two sources of divergence
A behavior is either specified — written in the AutoCAD reference document and/or the BricsCAD reference document — or merely exhibited — what the real product does, known only from probes. Warnings are driven by divergence between these, judged symmetrically: divergence is a relation between implementations, so if one implementation diverges on a value, they all diverge on it. A majority behavior does not thereby become "right".
The four cases
For each (function, argument-shape) clautolisp classifies the behavior:
| # | Situation | Behavior clautolisp performs, by dialect | Warns |
|---|---|---|---|
| 0 | Common. Both documents specify the | the common behavior | nobody |
| same and both products match. | |||
| 1 | Extension. Specified/present for some | clautolisp (a superset) performs the owning vendor's behavior in every dialect | every dialect except the owner and lax |
| implementations only. | |||
| 2 | Divergence (resolved). Vendors behave | the autolisp-spec ADOPTS one vendor as normative (the *** clautolisp note records which and why — the |
the deviant (non-adopted) vendor's |
| differently — the DOCUMENTS differ, or a | better-specified vendor, historically AutoCAD). The adopted-vendor dialect and clautolisp perform the |
dialect, and strict (lax silent) |
|
| product contradicts an agreed document; | normative behavior silently; strict performs it but WARNS (any divergence is unsafe to rely on); the |
||
| the autolisp-spec resolves it. | DEVIANT vendor's dialect reproduces the other behavior and warns (recognised, not condoned); lax |
||
| does the most useful thing, silent. | |||
| 3 | Divergence (unresolved, symmetric). The | each vendor dialect its own document's behavior; clautolisp picks one; strict the safe / |
every dialect except lax (symmetric) |
| autolisp-spec adopts NEITHER — genuinely | most-restrictive one | ||
| irreconcilable, no portable-safe choice. |
Dialect roles
lax— do whatever is most useful to the program; never warn.--autocad/--bricscad— reproduce that product's real behavior. Silent for that product's own extensions and for behavior the autolisp-spec adopts as normative. A vendor dialect warns only when it reproduces a divergence the autolisp-spec did not adopt from it — the deviant side of a resolved divergence (case 2), or either side of an unresolved one (case 3). The diagnostic is on*error-output*and does not disturb the value-faithful reproduction.clautolisp— the superset. For an extension it runs it; for a divergence it performs the autolisp-spec's adopted normative behavior (case 2) or its own recorded pick (case 3); the choice is stated in the function's*** clautolispnote. It is silent whenever its behavior is the adopted/normative one, and warns only in case 3.strict— the portable/conservative choice: it performs the adopted normative behavior (case 2) or the safe / most-restrictive one (case 3), and it warns whenever any other dialect would — on every extension used outside its owning dialect, and on every divergence, resolved or not, because a divergence of any kind makes the feature unsafe to rely on. Code that runs clean (no warning) understrictis portable.
Resolution, symmetry, and error
- Resolution. The autolisp-spec is clautolisp's normative reference;
when vendors diverge it normally ADOPTS one vendor's behavior as
normative — typically the one with the explicit, coherent
specification (historically AutoCAD, the reference AutoLISP). The
other vendor's behavior is then recognised but not condoned: only
its dialect (and
strict) warn, whileclautolispand the adopted vendor's dialect perform the normative behavior silently. Record the adoption, with its documentary evidence, in the function's*** clautolispnote. - Symmetry (residual). Only when the autolisp-spec adopts NEITHER
vendor (case 3) is the warning fully symmetric — every dialect except
lax— because no behavior is privileged. A majority behavior does not make it "right". Classifying a difference as case 2 (resolved) vs case 3 (unresolved) needs probe results matched against both reference documents; until that evidence exists, treat it as case 3 (symmetric) so no vendor is wrongly blamed. - Strict warns on any divergence. Independently of the case,
strictemits a warning whenever the active feature diverges across vendors — the purpose ofstrictis to surface every portability hazard, not to pick winners. It still performs the adopted or safe behavior; only the warning is unconditional. - Error is a behavior. A dialect's chosen behavior may be to signal an
error (AutoLISP-level:
nil+ERRNO, or an*error*exit). The warning, when due, is issued before the error. A hard abort of an otherwise-running program happens only under the opt-in--portability-warning-mode errorescalation (see the*** Statementabove), never as a dialect default.
Message form
Each warning carries a distinct bracketed tag naming the construct
(e.g. [lambda-list-extension], [terpri-file-extension]), the active
dialect, and, where useful, the fix. Tests key on the tag substring.
The once-per-occurrence rule below applies to every case.
Runtime semantics (executing implementation)
In an executing implementation such as clautolisp the warning is a
run-time event, tied to evaluation, not to mere textual presence:
- A warning is emitted only when the incompatible construct is actually reached during evaluation. A construct guarded behind a feature test — for example, code that probes whether the running implementation supports an extension and avoids it when it does not — is never evaluated on a host that lacks it, and therefore produces no warning and causes nothing wrong to happen.
- Each distinct source occurrence warns at most once per run, on its
first evaluation. The first time
foo(adefunusing&rest) is evaluated, the warning prints; subsequent evaluations of the samefoo— including evaluations inside a loop — are silent. - A different occurrence warns separately: if
baralso uses&rest, the first evaluation ofbarprints its own warning, independently offoo's. The dedup key is the occurrence, not the construct class. - For
defunspecifically the warning attaches to the definition site, so it is rare in practice (once per definition); for warnings about a specific function or argument usage the trigger is the call site, but the same once-per-occurrence rule applies — an incompatible expression executed repeatedly warns only on its first execution.
A representative message form:
DIALECT WARNING: DEFUN FOO with &REST only works in bricscad and clautolisp
Contrast with static analysis
A static-analysis tool built on the same knowledge base behaves
differently by necessity: it must report every potentially incompatible
occurrence whether or not it is ever evaluated, because it generally
cannot prove that a given expression is unreachable or guarded. Thus the
run-time discipline ("warn once, and only for what actually executes")
and the static discipline ("flag every occurrence") are two consumers of
one portability knowledge base — the catalogue of which constructs are
supported by which host/dialect. The same catalogue feeds the
clautolisp run-time warnings and any external static linter.
Cross-references
- Chapter 24, "BricsCAD Extensions" — the constructs that drive these
warnings (e.g.
defun&rest). - Chapter 27, "Version Compatibility and Portability" — the tagging axes (product / version / platform / strict-lax) the knowledge base records.
- Chapter 3,
:unbound-variable-mode:strict-error— precedent for a dialect-descriptor diagnostic knob and warning→error escalation.
Source Notes
- Design intent recorded for clautolisp; the warning catalogue is shared between the run-time emitter and any static-analysis tooling.
- Status: design stated; per-construct coverage and tests tracked as a clautolisp implementation issue.