-
Notifications
You must be signed in to change notification settings - Fork 10
/
declar.tex
2089 lines (1898 loc) · 99.5 KB
/
declar.tex
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
%Part{Declar, Root = "CLM.MSS"}
%Chapter of Common Lisp Manual. Copyright 1984, 1988, 1989 Guy L. Steele Jr.
\clearpage\def\pagestatus{ULTIMATE}
\ifx \rulang\Undef
\chapter{Declarations}
\label{DECLAR}
Declarations allow you to specify extra information about your program
to the Lisp system. With one exception,
declarations are completely optional
and correct declarations do not affect the meaning
of a correct program. The exception is that
\cdf{special} declarations \emph{do} affect the interpretation of variable
bindings and references and so \emph{must} be specified where appropriate.
All other declarations are of an advisory nature, and may be used
by the Lisp system to aid the programmer by performing extra error checking
or producing more efficient compiled code. Declarations are also
a good way to add documentation to a program.
Note that it is considered an error for a program to violate a
declaration (such as a \cdf{type} declaration), but an implementation is
not required to detect such errors (though such detection, where
feasible, is to be encouraged).
\section{Declaration Syntax}
\label{DECLARE-SYNTAX-SECTION}
The \cdf{declare} construct is used for embedding declarations within
executable code. Global declarations and declarations that are computed
by a program are established by the \cdf{proclaim} construct.
Macro \cdf{declaim}, which is guaranteed
to be recognized appropriately by the compiler, is often more convenient
than \cdf{proclaim} for establishing global declarations.
\begin{defspec}
declare {decl-spec}*
A \cdf{declare} form is known as a \emph{declaration}.
Declarations may occur only at the beginning of the bodies of
certain special operators;
that is, a declaration may occur only as a statement
of such a special operator, and all statements preceding it (if any) must
also be \cdf{declare} forms (or possibly documentation strings, in some cases).
Declarations may occur in lambda-expressions and in the forms listed here.
\begin{lisp}
\hskip 12pc\=\kill
\cdf{define-setf-method}\>\cdf{labels} \\*
\cdf{defmacro}\>\cdf{let} \\*
\cdf{defsetf}\>\cdf{let*} \\*
\cdf{deftype}\>\cdf{locally} \\
\cdf{defun}\>\cdf{macrolet} \\
\cdf{do}\>\cdf{multiple-value-bind} \\
\cdf{do*}\>\cdf{prog} \\
\cdf{do-all-symbols}\>\cdf{prog*} \\
\cdf{do-external-symbols}\>\cdf{with-input-from-string} \\
\cdf{do-symbols}\>\cdf{with-open-file} \\
\cdf{dolist}\>\cdf{with-open-stream} \\*
\cdf{dotimes}\>\cdf{with-output-to-string} \\*
\cdf{flet}\>\cdf{with-conditions-restarts} \\
\cdf{print-unreadable-object}\>\cdf{with-standard-io-syntax}
\end{lisp}
\begin{lisp}
\hskip 12pc\=\kill
\cdf{defgeneric}\>\cdf{generic-function} \\*
\cdf{define-method-combination}\>\cdf{generic-labels} \\*
\cdf{defmethod} %\>\cdf{with-added-methods} \\*
%\cdf{generic-flet}
\end{lisp}
\begin{lisp}
\hskip 12pc\=\kill
\cdf{symbol-macrolet}\>\cdf{with-slots} \\*
\cdf{with-accessors}
\end{lisp}
It is an error to attempt to evaluate a declaration.
Those special operators that permit declarations to appear
perform explicit checks for their presence.
It is permissible for a macro call to expand into a declaration
and be recognized as such, provided that the macro call
appears where a declaration may legitimately appear.
(However, a macro call may not appear in place of a \emph{decl-spec}.)
A declaration is recognized only as such if
it appears explicitly, as a list whose \emph{car} is the symbol \cdf{declare},
in the body of a relevant special operator. (Note, however, that it
is still possible for a macro to expand into a call to the \cdf{proclaim}
function.)
Each \emph{decl-spec} is a list whose \emph{car} is a symbol
specifying the kind of declaration to be made. Declarations may be
divided into two classes: those that concern the bindings of variables,
and those that do not. (The \cdf{special} declaration is the sole
exception: it effectively falls into both classes, as explained below.)
Those that concern variable bindings apply
only to the bindings made by the form at the head of whose body they
appear. For example, in
\begin{lisp}
(defun foo (x) \\
~~(declare (type float x)) ... \\
~~(let ((x 'a)) ...) \\
~~...)
\end{lisp}
the \cdf{type} declaration applies only to the outer binding of \cdf{x},
and not to the binding made in the \cdf{let}.
Declarations that do not concern themselves with variable bindings are
pervasive, affecting all code in the body of the special operator.
As an example of a pervasive declaration,
\begin{lisp}
(defun foo (x y) (declare (notinline floor)) ...)
\end{lisp}
advises that everywhere within the body of \cdf{foo} the function
\cdf{floor} should not be open-coded but called as an out-of-line subroutine.
Some special operators contain pieces of code that, properly speaking,
are not part of the body of the special operator. Examples of this
are initialization forms that provide values for bound variables,
and the result forms of iteration constructs.
In all cases such additional code is within the scope of any pervasive
declarations appearing before the body of the special operator.
Non-pervasive declarations have no effect on such code, except (of course)
in those situations where the code is defined to be within the scope
of the variables affected by such non-pervasive declarations.
For example:
\begin{lisp}
(defun few (x \cd{\&optional} (y *print-circle*)) \\*
~~(declare (special *print-circle*)) \\*
~~...)
\end{lisp}
The reference to \cdf{*print-circle*} in the first line of this example is special
because of the declaration in the second line.
\begin{lisp}
(defun nonsense (k x z) \\*
~~(foo z x)~~~~~~~~~~~~~~~;\textrm{First call to \cdf{foo}} \\*
~~(let ((j (foo k x))~~~~~;\textrm{Second call to \cdf{foo}} \\*
~~~~~~~~(x (* k k))) \\*
~~~~(declare (inline foo) (special x z)) \\*
~~~~(foo x j z)))~~~~~~~~~;\textrm{Third call to \cdf{foo}}
\end{lisp}
In this rather nonsensical example,
the \cdf{inline} declaration applies to the
second and third calls to \cdf{foo}, but not to the first one.
The \cdf{special} declaration of \cdf{x} causes the \cdf{let} form
to make a special binding for \cdf{x} and causes the reference to \cdf{x}
in the body of the \cdf{let} to be a special reference.
The reference to \cdf{x} in the second call to \cdf{foo} is also a special
reference.
The reference to \cdf{x} in the first call to \cdf{foo} is a local
reference, not a special one. The \cdf{special} declaration of \cdf{z}
causes the reference to \cdf{z} in the call
to \cdf{foo} to be a special reference; it will not
refer to the parameter to \cdf{nonsense} named \cdf{z}, because that
parameter binding has not been declared to be \cdf{special}.
(The \cdf{special} declaration of \cdf{z} does not appear in the body
of the \cdf{defun}, but in an inner construct, and therefore does not
affect the binding of the parameter.)
\begin{new}
X3J13 voted in January 1989
\issue{DECLARATION-SCOPE}
to replace the rules concerning the scope of
declarations occurring at the head of a special operator or lambda-expression:
\begin{itemize}
\item The scope of a declaration always includes the body forms, as well as any
``stepper'' or ``result'' forms (which are logically part of the body), of the
special operator or lambda-expression.
\item If the declaration applies to a name binding, then the scope of the
declaration also includes the scope of the name binding.
\end{itemize}
Note that
the distinction between pervasive and non-pervasive
declarations is eliminated. An important change
from the first edition is that ``initialization''
forms are specifically \emph{not} included as part of the body under the first
rule; on the other hand, in many cases initialization forms may fall
within the scope of certain declarations under the second rule.
\end{new}
\begin{new}
X3J13 also voted in January 1989
\issue{DECLARE-TYPE-FREE}
to change the interpretation
of \cdf{type} declarations (see section \ref{DECLARATION-SPECIFIERS-SECTION}).
\end{new}
\begin{new}
These changes affect the interpretation of some of the examples from the
first edition.
\begin{lisp}
(defun foo (x) \\*
~~(declare (type float x)) ... \\*
~~(let ((x 'a)) ...) \\*
~~...)
\end{lisp}
Under the interpretation approved by X3J13, the type
declaration applies to \emph{both} bindings of \cdf{x}.
More accurately, the type declaration is considered to apply to
variable references rather than bindings, and the type declaration refers
to every reference in the body of \cdf{foo} to a variable named \cdf{x},
no matter to what binding it may refer.
\begin{lisp}
(defun foo (x y) (declare (notinline floor)) ...)
\end{lisp}
This example of the use of \cdf{notinline} stands unchanged, but the following
slight extension of it would change:
\begin{lisp}
(defun foo (x \&optional (y (floor x))) \\*
~~(declare (notinline floor)) ...)
\end{lisp}
Under first edition rules, the \cdf{notinline} declaration would be
considered to apply to the call to \cdf{floor} in the initialization
form for \cdf{y}. Under the interpretation approved by X3J13, the
\cdf{notinline} would \emph{not} apply to that particular call to \cdf{floor}.
Instead the user must write something like
\begin{lisp}
(defun foo (x \&optional (y (locally (declare (notinline floor)) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(floor x)))) \\*
~~(declare (notinline floor)) ...)
\end{lisp}
or perhaps
\begin{lisp}
(locally (declare (notinline floor)) \\*
~~(defun foo (x \&optional (y (floor x))) ...))
\end{lisp}
Similarly, the \cdf{special} declaration in
\begin{lisp}
(defun few (x \cd{\&optional} (y *print-circle*)) \\*
~~(declare (special *print-circle*)) \\*
~~...)
\end{lisp}
is not considered to apply to the reference in the initialization form
for \cdf{y} in \cdf{few}. As for the \cdf{nonsense} example,
\begin{lisp}
(defun nonsense (k x z) \\*
~~(foo z x)~~~~~~~~~~~~~~~;\textrm{First call to \cdf{foo}} \\*
~~(let ((j (foo k x))~~~~~;\textrm{Second call to \cdf{foo}} \\*
~~~~~~~~(x (* k k))) \\*
~~~~(declare (inline foo) (special x z)) \\*
~~~~(foo x j z)))~~~~~~~~~;\textrm{Third call to \cdf{foo}}
\end{lisp}
under the interpretation approved by X3J13, the \cdf{inline}
declaration is no longer considered to apply to the second
call to \cdf{foo}, because it is in an initialization form, which is
no longer considered in the scope of the declaration. Similarly,
the reference to \cdf{x} in that second call to \cdf{foo} is no longer
taken to be a special reference, but a local reference to the second
parameter of \cdf{nonsense}.
\end{new}
\end{defspec}
\cdf{locally} executes the \emph{form\/}s as an implicit
\cdf{progn} and returns the value(s) of the last \emph{form}.
\begin{defspec}
locally {declaration}* {form}*
This change was made to accommodate the new compilation model for top-level forms
in a file (see section~\ref{COMPILER-SECTION}).
When a \cdf{locally} operator appears at top level, the forms in its body are
processed as top-level forms. This means that one may, for example, meaningfully use
\cdf{locally} to wrap declarations around a \cdf{defun} or \cdf{defmacro} form:
\begin{lisp}
(locally \\*
~~(declare (optimize (safety 3) (space 3) (debug 3) (speed 1))) \\*
~~(defun foo (x \&optional (y (abs x)) (z (sqrt y))) \\*
~~~~(bar x y z)))
\end{lisp}
Without assurance that this works
one must write something cumbersome such as
\begin{lisp}
\\*
(defun foo (x \&optional (y (locally \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(declare (optimize (safety 3) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(space 3) \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(debug 3) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(speed 1))) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(abs x))) \\
~~~~~~~~~~~~~~~~~~~~~~~~~(z (locally \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(declare (optimize (safety 3) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(space 3) \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(debug 3) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(speed 1))) \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(sqrt y)))) \\
~~(locally \\*
~~~~(declare (optimize (safety 3) (space 3) (debug 3) (speed 1))) \\*
~~~~(bar x y z)))
\end{lisp}
\end{defspec}
\begin{defun}[Function]
proclaim decl-spec
The function \cdf{proclaim} takes a \emph{decl-spec} as its
argument and puts it into effect globally. (Such a global
declaration is called a \emph{proclamation}.)
Because \cdf{proclaim} is a function, its argument is always evaluated.
This allows a program to compute a declaration and then put
it into effect by calling \cdf{proclaim}.
Any variable names
mentioned are assumed to refer to the dynamic values of the
variable. For example, the proclamation
\begin{lisp}
(proclaim '(type float tolerance))
\end{lisp}
once executed,
specifies that the dynamic value of \cdf{tolerance} should always
be a floating-point number.
Similarly, any function-names mentioned are assumed to refer to
the global function definition.
A proclamation constitutes a universal declaration, always in force
unless locally shadowed. For example,
\begin{lisp}
(proclaim '(inline floor))
\end{lisp}
advises that \cdf{floor} should normally be open-coded in-line by the
compiler (but in the situation
\begin{lisp}
(defun foo (x y) (declare (notinline floor)) ...)
\end{lisp}
it will be compiled out-of-line anyway in the body of \cdf{foo},
because of the shadowing local declaration to that effect).
\begin{newer}
X3J13 voted in January 1989 \issue{SPECIAL-TYPE-SHADOWING}
to clarify that such shadowing does not occur in the case of type declarations.
If there is a local type declaration for a special variable and there is also a global
proclamation for that same variable, then the value of the variable within the scope
of the local declaration must be a member of the intersection of the two
declared types.
This is consistent with the treatment of nested local type declarations
on which X3J13 also voted in January 1989 \issue{DECLARE-TYPE-FREE}.
\end{newer}
As a special case (so to speak), \cdf{proclaim} treats a \cdf{special}
\emph{decl-spec} as applying to all bindings as well as to
all references of the mentioned variables.
\begin{new}%CORR
\emph{Notice of correction.}
In the first edition, this sentence referred to a ``\cdf{special}
\emph{declaration-form}.'' That was incorrect; \cdf{proclaim} accepts
only a \emph{decl-spec}, not a \emph{declaration-form}.
\end{new}
For example, after
\begin{lisp}
(proclaim '(special x))
\end{lisp}
in a function definition such as
\begin{lisp}
(defun example (x) ...)
\end{lisp}
the parameter \cdf{x} will be bound as a special (dynamic) variable
rather than as a lexical (static) variable. This facility should
be used with caution. The usual way to define a globally special
variable is with \cdf{defvar} or \cdf{defparameter}.
\end{defun}
\begin{defmac}
declaim {decl-spec}*
This macro is syntactically like \cdf{declare} and semantically
like \cdf{proclaim}. It is an executable form and may be used
anywhere \cdf{proclaim} may be called. However, each \emph{decl-spec}
is not evaluated.
If a call to this macro appears at top level in a file
being processed by the file compiler, the proclamations are also
made at compile time. As with other defining macros, it is
unspecified whether or not the compile-time side effects of a
\cdf{declaim} persist after the file has been compiled
(see section~\ref{COMPILER-SECTION}).
\end{defmac}
\section{Declaration Specifiers}
\label{DECLARATION-SPECIFIERS-SECTION}
Here is a list of valid declaration specifiers for use in
\cdf{declare}. A construct is said to be ``affected'' by a declaration
if it occurs within the scope of a declaration.
\begin{flushdesc}
\item[\cdf{special}]
\cd{(special \emph{var1} \emph{var2} ...)} specifies that all of
the variables named are to be considered \emph{special}.
This specifier affects variable bindings but also pervasively
affects references.
All variable bindings affected are made to be dynamic bindings,
and affected variable references refer to the current dynamic binding
rather than to the current local binding.
For example:
\begin{lisp}
(defun hack (thing *mod*)~~~~~~~;\textrm{The binding of the parameter} \\
~~(declare (special *mod*))~~~~~; \textrm{\cd{*mod*} is visible to \cd{hack1},} \\
~~(hack1 (car thing)))~~~~~~~~~~; \textrm{but not that of \cdf{thing}} \\
\\
(defun hack1 (arg) \\
~~(declare (special *mod*))~~~~~;\textrm{Declare references to \cd{*mod*}} \\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~; \textrm{within \cd{hack1} to be special} \\
~~(if (atom arg) *mod* \\
~~~~~~(cons (hack1 (car arg)) (hack1 (cdr arg)))))
\end{lisp}
Note that it is conventional, though not required, to give special
variables names that begin and end with an asterisk.
A \cdf{special} declaration does \emph{not} affect bindings pervasively.
Inner bindings of a variable implicitly shadow
a \cdf{special} declaration and must be explicitly re-declared to
be special.
(However, a \cdf{special} proclamation \emph{does} pervasively affect bindings;
this exception is made for reasons of
convenience and compatibility with MacLisp.)
For example:
\begin{lisp}
(proclaim '(special x))~~~~~;\textrm{\cdf{x} is always special} \\
\\
(defun example (x y) \\
~~(declare (special y)) \\
~~(let ((y 3) (x (* x 2))) \\
~~~~(print (+ y (locally (declare (special y)) y))) \\
~~~~(let ((y 4)) (declare (special y)) (foo x))))
\end{lisp}
In the contorted code above, the outermost and innermost bindings of
\cdf{y} are special and therefore dynamically scoped, but the middle
binding is lexically scoped. The two arguments to \cdf{+} are different,
one being the value, which is \cd{3}, of the lexically bound variable
\cdf{y}, and the other being the value of the special variable named \cdf{y}
(a binding of which happens, coincidentally, to lexically surround it at
an outer level). All the bindings of \cdf{x} and references to \cdf{x}
are special, however, because of the proclamation that \cdf{x} is
always \cdf{special}.
As a matter of style, use of \cdf{special} proclamations should be
avoided. The \cdf{defvar} and \cdf{defparameter} macros
are the conventional means for proclaiming special variables
in a program.
\item[\cdf{type}]
\cd{(type \emph{type} \emph{var1} \emph{var2} ...)} affects
only variable bindings and specifies that the
variables mentioned will take on values only of the specified type.
In particular, values assigned to the variables by \cdf{setq},
as well as the initial values of the variables, must be of
the specified type.
\begin{new}
X3J13 voted in January 1989
\issue{DECLARE-TYPE-FREE}
to alter the interpretation of type declarations.
They are not to be construed to affect ``only variable bindings.''
The new rule for a declaration of a variable to
have a specified type is threefold:
\begin{itemize}
\item It is an error if, during the execution
of any reference to that variable within the scope of the declaration,
the value of the variable is not of the declared type.
\item It is an error if, during the execution
of a \cdf{setq} of that variable within the scope of the declaration,
the new value for the variable is not of the declared type.
\item It is an error if, at any moment that execution enters the scope
of the declaration, the value of the variable is not of the
declared type.
\end{itemize}
One may think of a type declaration \cd{(declare (type face bodoni))}
as implicitly changing every reference to \cdf{bodoni} within the scope
of the declaration to \cd{(the~face bodoni)}; changing every expression
\emph{exp} assigned to \cdf{bodoni} within the scope of the declaration
to \cd{(the~face \emph{exp})}; and implicitly executing \cd{(the~face bodoni)}
every time execution enters the scope of the declaration.
These new rules make type declarations much more useful. Under first
edition rules, a type declaration was useless if not associated with
a variable binding; declarations such as in
\begin{lisp}
(locally \\*
~~(declare (type (byte 8) x y)) \\*
~~(+ x y))
\end{lisp}
at best had no effect and at worst were erroneous, depending on one's
interpretation of the first edition. Under the interpretation approved
by X3J13, such declarations have ``the obvious natural interpretation.''
X3J13 noted that if nested type declarations refer to the same variable,
then all of them have effect; the value of the variable must be a member of the
intersection of the declared types.
Nested type declarations could occur as a result of either macro expansion
or carefully crafted code. There are three cases. First,
the inner type might be a subtype of the outer one:
\begin{lisp}
(defun compare (apples oranges) \\*
~~(declare (type number apples oranges)) \\
~~(cond ((typep apples 'fixnum) \\*
~~~~~~~~~;; The programmer happens to know that, thanks to \\*
~~~~~~~~~;; constraints imposed by the caller, if APPLES \\*
~~~~~~~~~;; is a fixnum, then ORANGES will be also, and \\*
~~~~~~~~~;; therefore wishes to avoid the unnecessary cost \\*
~~~~~~~~~;; of checking ORANGES.~~Nevertheless the compiler \\*
~~~~~~~~~;; should be informed to allow it to optimize code. \\
~~~~~~~~~(locally (declare (type fixnum apples oranges))) \\*
~~~~~~~~~~~~~~~~~~;; Maybe the compiler could have figured \\*
~~~~~~~~~~~~~~~~~~;; out by flow analysis that APPLES must \\*
~~~~~~~~~~~~~~~~~~;; be a fixnum here, but it doesn't hurt \\*
~~~~~~~~~~~~~~~~~~;; to say it explicitly. \\*
~~~~~~~~~~~(< apples oranges))) \\
~~~~~~~~((or (complex apples) \\*
~~~~~~~~~~~~~(complex oranges)) \\*
~~~~~~~~~(error "Not yet implemented.~~Sorry.")) \\*
~~~~~~~~...))
\end{lisp}
This is the case most likely to arise in code written completely by hand.
Second, the outer type might be a subtype of the inner one. In this
case the inner declaration has no additional practical effect, but
it is harmless. This is
likely to occur if code declares a variable to be of a very specific type
and then passes it to a macro that then declares it to be of a less
specific type.
Third, the inner and outer declarations might be for types that
overlap, neither being a subtype of the other. This is likely to occur
only as a result of macro expansion. For example, user code might
declare a variable to be of type \cdf{integer}, and a macro might
later declare it to be of type \cd{(or fixnum package)}; in this case
a compiler could intersect the two types to determine that in this
instance the variable may hold only fixnums.
The reader should note that the following code fragment is,
perhaps astonishingly, \emph{not in error} under the interpretation approved by
X3J13:
\begin{lisp}
(let ((james .007) \\*
~~~~~~(maxwell 86)) \\*
~~(flet ((spy-swap () \\*
~~~~~~~~~~~(rotatef james maxwell))) \\*
~~~~(locally (declare (integer maxwell)) \\*
~~~~~~(spy-swap) \\*
~~~~~~(view-movie "The Sound of Music") \\*
~~~~~~(spy-swap) \\*
~~~~~~maxwell))) \\*
~\EV\ 86~~\textrm{(after a couple of hours of Julie Andrews)}
\end{lisp}
The variable \cdf{maxwell} is declared to be an integer over the \emph{scope}
of the type declaration, not over its \emph{extent}. Indeed \cdf{maxwell}
takes on the non-integer value \cd{.007} while the Trapp family make their
escape, but because no
reference to \cdf{maxwell} within the scope of the declaration
ever produces a non-integer value, the code
is correct.
Now the assignment to \cdf{maxwell} during the first call
to \cdf{spy-swap}, and the reference to \cdf{maxwell} during the second call,
\emph{do} involve non-integer values, but they occur within the body of
\cdf{spy-swap}, which is \emph{not} in the scope of the type declaration!
One could put the declaration in a different place so as to include
\cdf{spy-swap} in the scope:
\begin{lisp}
(let ((james .007) \\*
~~~~~~(maxwell 86)) \\*
~~(locally (declare (integer maxwell)) \\*
~~~~(flet ((spy-swap () \\*
~~~~~~~~~~~~~(rotatef james maxwell))) \\*
~~~~~~(spy-swap)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Bug!}\\*
~~~~~~(view-movie "The Sound of Music") \\*
~~~~~~(spy-swap) \\*
~~~~~~maxwell)))
\end{lisp}
and then the code is indeed in error.
\end{new}
\begin{new}
X3J13 also voted in January 1989
\issue{FUNCTION-TYPE-ARGUMENT-TYPE-SEMANTICS}
to alter the meaning of the
\cdf{function} type specifier when used in \cdf{type} declarations
(see section~\ref{SPECIALIZED-TYPE-SPECIFIER-SECTION}).
\end{new}
\item[\emph{type}]
\cd{(\emph{type} \emph{var1} \emph{var2} ...)}
is an abbreviation for
\cd{(type \emph{type} \emph{var1} \emph{var2} ...)},
provided that \emph{type} is one of the symbols appearing
in table~\ref{TYPE-SYMBOLS-TABLE}.
\begin{new}
Observe that this covers the particularly common case of declaring
numeric variables:
\begin{lisp}
(declare (single-float mass dx dy dz) \\*
~~~~~~~~~(double-float acceleration sum))
\end{lisp}
In many implementations there is also some advantage to declaring variables
to have certain specialized vector types such as \cdf{base-string}.
\end{new}
\item[\cdf{ftype}]
\cd{(ftype \emph{type} \emph{function-name-1} \emph{function-name-2} ...)}
specifies that the named functions will be of the functional type
\emph{type}, an example of which follows.
For example:
\begin{lisp}
(declare (ftype (function (integer list) t) nth) \\*
~~~~~~~~~(ftype (function (number) float) sin cos))
\end{lisp}
Note that rules of lexical scoping are observed; if one of the functions
mentioned has a lexically apparent local definition
(as made by \cdf{flet} or \cdf{labels}), then the declaration
applies to that local definition and not to the global function definition.
\begin{newer}
X3J13 voted in March 1989 \issue{FUNCTION-NAME} to extend \cdf{ftype}
declaration specifiers
to accept any function-name (a symbol or a list
whose \emph{car} is \cdf{setf}---see section~\ref{FUNCTION-NAME-SECTION}).
Thus one may write
\begin{lisp}
(declaim (ftype (function (list) t) (setf cadr)))
\end{lisp}
to indicate the type of the \cdf{setf} expansion function for \cdf{cadr}.
\end{newer}
\begin{new}
X3J13 voted in January 1989
\issue{FUNCTION-TYPE-ARGUMENT-TYPE-SEMANTICS}
to alter the meaning of the
\cdf{function} type specifier when used in \cdf{ftype} declarations
(see section~\ref{SPECIALIZED-TYPE-SPECIFIER-SECTION}).
\end{new}
\end{flushdesc}
\begin{new}
X3J13 voted in January 1989
\issue{DECLARE-FUNCTION-AMBIGUITY}
to remove this interpretation
of the \cdf{function} declaration specifier from the language.
Instead, a declaration specifier
\begin{lisp}
(function \emph{var1} \emph{var2} ...)
\end{lisp}
is to be treated simply as an abbreviation for
\begin{lisp}
(type function \emph{var1} \emph{var2} ...)
\end{lisp}
just as for all other symbols appearing in table~\ref{TYPE-SYMBOLS-TABLE}.
X3J13 noted that although \cdf{function} appears in
table~\ref{TYPE-SYMBOLS-TABLE}, the first edition also discussed it
explicitly, with a different meaning,
without noting whether the differing
interpretation was to replace or augment the
interpretation regarding table~\ref{TYPE-SYMBOLS-TABLE}. Unfortunately
there is an ambiguous case: the declaration
\begin{lisp}
(declare (function foo nil string))
\end{lisp}
can be construed to abbreviate either
\begin{lisp}
(declare (ftype (function () string) foo))
\end{lisp}
or
\begin{lisp}
(declare (type function foo nil string))
\end{lisp}
The latter could perhaps be rejected on semantic grounds: it would be an
error to declare \cdf{nil}, a constant, to be of type \cdf{function}.
In any case, X3J13 determined that the ice was too thin here;
the possibility of confusion is not worth the convenience of
an abbreviation for \cdf{ftype} declarations.
The change also makes the language more consistent.
\end{new}
\begin{flushdesc}
\item[\cdf{inline}]
\cd{(inline \emph{function1} \emph{function2} ...)} specifies that
it is desirable for the compiler to open-code
calls to the specified functions; that is, the code for a specified function
should be integrated into the calling routine, appearing in-line
in place of a procedure call. This may achieve
extra speed at the expense of debuggability (calls to functions
compiled in-line cannot be traced, for example).
This declaration is pervasive.
Remember that
a compiler is free to ignore this declaration.
Note that rules of lexical scoping are observed; if one of the functions
mentioned has a lexically apparent local definition
(as established by \cdf{flet} or \cdf{labels}), then the declaration
applies to that local definition and not to the global function definition.
\begin{newer}
X3J13 voted in October 1988 \issue{PROCLAIM-INLINE-WHERE}
to clarify that during compilation the \cdf{inline} declaration specifier
serves two distinct purposes: it indicates not only that affected calls
to the specified functions should be expanded in-line, but also that
affected definitions of the specified functions must be recorded for
possible use in performing such expansions.
Looking at it the other way,
the compiler is not required to save function definitions against the
possibility of future expansions unless the functions have already been
proclaimed to be \cdf{inline}. If a function is proclaimed (or declaimed)
\cdf{inline}
before some call to that function but the current definition of that
function was established before the proclamation was processed,
it is implementation-dependent whether that call will be expanded in-line.
(Of course, it is implementation-dependent anyway, because a compiler
is always free to ignore \cdf{inline} declaration specifiers.
However, the intent of the committee is clear: for best results,
the user is advised to put any \cdf{inline} proclamation of
a function before any definition of or call to that function.)
Consider these examples:
\begin{lisp}
(defun huey (x) (+ x 100))~~~~~~~~~;\textrm{Compiler need not remember this} \\*
(declaim (inline huey dewey)) \\*
(defun dewey (y) (huey (sqrt y)))~~;\textrm{Call to \cdf{huey} unlikely to be expanded} \\*
(defun louie (z) (dewey (/ z)))~~~~;\textrm{Call to \cdf{dewey} likely to be expanded}
\end{lisp}
\goodbreak
X3J13 voted in March 1989 \issue{FUNCTION-NAME} to extend \cdf{inline}
declaration specifiers
to accept any function-name (a symbol or a list
whose \emph{car} is \cdf{setf}---see section~\ref{FUNCTION-NAME-SECTION}).
Thus one may write \cd{(declare (inline (setf cadr)))} to indicate
that the \cdf{setf}
expansion function for \cdf{cadr} should be compiled in-line.
\end{newer}
\item[\cdf{notinline}]
\cd{(notinline \emph{function1} \emph{function2} ...)} specifies that it is
\emph{undesirable} to compile the specified functions in-line.
This declaration is pervasive.
A compiler is \emph{not} free to ignore this declaration.
Note that rules of lexical scoping are observed; if one of the functions
mentioned has a lexically apparent local definition
(as made by \cdf{flet} or \cdf{labels}), then the declaration
applies to that local definition and not to the global function definition.
\begin{newer}
X3J13 voted in March 1989 \issue{FUNCTION-NAME} to extend \cdf{notinline}
declaration specifiers
to accept any function-name (a symbol or a list
whose \emph{car} is \cdf{setf}---see section~\ref{FUNCTION-NAME-SECTION}).
Thus one may write \cd{(declare (notinline (setf cadr)))} to indicate
that the \cdf{setf}
expansion function for \cdf{cadr} should not be compiled in-line.
\end{newer}
\begin{new}
X3J13 voted in January 1989
\issue{ALLOW-LOCAL-INLINE}
to clarify that the proper way to define a function \cdf{gnards}
that is not \cdf{inline} by default, but for which a local
declaration \cd{(declare (inline~gnards))} has half a chance of
actually compiling \cdf{gnards} in-line, is as follows:
\begin{lisp}
(declaim (inline gnards)) \\*
\\*
(defun gnards ...) \\*
\\*
(declaim (notinline gnards))
\end{lisp}
The point is that the first declamation informs the compiler that
the definition of \cdf{gnards} may be needed later for in-line expansion,
and the second declamation prevents any expansions unless and until it is
overridden.
While an implementation is never required to perform in-line expansion,
many implementations that do support such expansion will not
process \cdf{inline} requests successfully unless definitions are
written with these proclamations in the manner shown above.
\end{new}
\item[\cdf{ignore}]
\cd{(ignore \emph{var1} \emph{var2} ... \emph{varn})} affects only variable bindings
and specifies that the bindings
of the specified variables are never used. It is desirable for a compiler
to issue a warning if a variable so declared is ever referred to
or is also declared special, or if a variable is lexical, never referred to,
and not declared to be ignored.
\item[\cdf{optimize}]
\cd{(optimize (\emph{quality1} \emph{value1}) (\emph{quality2} \emph{value2})...)}
advises the compiler that each \emph{quality} should be given attention
according to the specified corresponding \emph{value}.
A quality is a symbol; standard qualities
include \cdf{speed} (of the object code), \cdf{space} (both code size and
run-time space), \cdf{safety} (run-time error checking),
and \cdf{compilation-speed} (speed of the compilation process).
\begin{newer}
X3J13 voted in October 1988 \issue{OPTIMIZE-DEBUG-INFO} to add
the standard quality \cdf{debug} (ease of debugging).
\end{newer}
Other qualities may be recognized by particular implementations.
A \emph{value} should be a non-negative integer, normally in the range
\cd{0} to \cd{3}. The value \cd{0} means that the quality is totally
unimportant, and \cd{3} that the quality is extremely important;
\cd{1} and \cd{2} are intermediate values, with \cd{1} the ``normal''
or ``usual'' value.
One may abbreviate \cd{(\emph{quality} 3)} to simply \emph{quality}.
This declaration is pervasive.
For example:
\begin{lisp}
(defun often-used-subroutine (x y) \\*
~~(declare (optimize (safety 2))) \\*
~~(error-check x y) \\*
~~(hairy-setup x) \\
~~(do ((i 0 (+ i 1)) \\*
~~~~~~~(z x (cdr z))) \\*
~~~~~~((null z) i) \\
~~~~;; This inner loop really needs to burn. \\*
~~~~(declare (optimize speed)) \\*
~~~~(declare (fixnum i)) \\*
~~~~)))
\end{lisp}
\item[\cdf{declaration}]
\cd{(declaration \emph{name1} \emph{name2} ...)} advises the compiler
that each \emph{namej} is a valid but non-standard declaration name.
The purpose of this is to tell one compiler not to issue warnings
for declarations meant for another compiler or other program processor.
The \cdf{declaration} declaration specifier may be used with \cdf{declaim}
as well as \cdf{proclaim}. The preceding examples would be better written
using \cdf{declaim}, to ensure that the compiler will process them properly.
\begin{lisp}
(declaim (declaration author \\*
~~~~~~~~~~~~~~~~~~~~~~target-language \\*
~~~~~~~~~~~~~~~~~~~~~~target-machine)) \\
\\
(declaim (target-language ada) \\*
~~~~~~~~~(target-machine IBM-650)) \\
\\
(defun strangep (x) \\*
~~(declare (author "Harry Tweeker")) \\*
~~(member x '(strange weird odd peculiar)))
\end{lisp}
\item[\cdf{dynamic-extent}]
\cd{(dynamic-extent \emph{item1} \emph{item2} ... \emph{itemn})} declares that
certain variables or function-names refer to data objects whose extents may be
regarded as dynamic; that is, the declaration may be construed as a guarantee on
the part of the programmer that the program will behave correctly even if the
data objects have only dynamic extent rather than the usual indefinite extent.
Each \emph{item} may be either a variable name or \cd{(function \emph{f\/})}
where \emph{f} is a function-name (see section~\ref{FUNCTION-NAME-SECTION}).
(Of course, \cd{(function \emph{f\/})} may be abbreviated in the usual way as
\cd{\#'\emph{f}}.)
It is permissible for an implementation simply to ignore this declaration. In
implementations that do not ignore it, the compiler (or interpreter) is free to
make whatever optimizations are appropriate given this information; the most
common optimization is to stack-allocate the initial value of the object. The
data types that can be optimized in this manner may vary from implementation to
implementation.
The meaning of this declaration can be stated more precisely. We say that
object \emph{x} is an \emph{otherwise inaccessible part} of \emph{y} if and only
if making \emph{y} inaccessible would make \emph{x} inaccessible. (Note that
every object is an otherwise inaccessible part of itself.) Now suppose that
construct \emph{c} contains a \cdf{dynamic-extent} declaration for variable (or
function) \emph{v} (which need not be bound by \emph{c}). Consider the values
$\emph{w}_1, \ldots, \emph{w}_{n}$ taken on by \emph{v}
during the course of some execution of \emph{c}. The declaration asserts that
if some object \emph{x} is an otherwise inaccessible part of
$\emph{w}_{j}$ whenever $\emph{w}_{j}$ becomes the value of \emph{v}, then just
after execution of $c$ terminates \emph{x} will be either inaccessible or still
an otherwise inaccessible part of the value of \emph{v}. If this assertion is
ever violated, the consequences are undefined.
In some implementations, it is possible to allocate data structures in a way
that will make them easier to reclaim than by general-purpose garbage collection
(for example, on the stack or in some temporary area). The \cdf{dynamic-extent}
declaration is designed to give the implementation the information necessary to
exploit such techniques.
For example, in the code fragment
\begin{lisp} (let ((x (list 'a1 'b1 'c1)) \\* ~~~~~~(y (cons 'a2 (cons 'b2 (cons
'c2 'd2))))) \\* ~~(declare (dynamic-extent x y)) \\* ~~...)
\end{lisp} it is not difficult to prove that the otherwise inaccessible parts of
\cdf{x} include the three conses constructed by \cdf{list}, and that the
otherwise inaccessible parts of \cdf{y} include three other conses manufactured
by the three calls to \cdf{cons}. Given the presence of the
\cdf{dynamic-extent} declaration, a compiler would be justified in
stack-allocating these six conses and reclaiming their storage on exit from the
\cdf{let} form.
Since stack allocation of the initial value entails knowing at the object's
creation time that the object can be stack-allocated, it is not generally useful
to declare \cdf{dynamic-extent} for variables that have no lexically apparent
initial value. For example,
\begin{lisp} (defun f () \\* ~~(let ((x (list 1 2 3))) \\* ~~~~(declare
(dynamic-extent x)) \\* ~~~~...))
\end{lisp} would permit a compiler to stack-allocate the list in
\cdf{x}. However,
\begin{lisp} (defun g (x) (declare (dynamic-extent x)) ...) \\* (defun f () (g
(list 1 2 3)))
\end{lisp} could not typically permit a similar optimization in \cdf{f} because
of the possibility of later redefinition of \cdf{g}. Only an implementation
careful enough to recompile \cdf{f} if the definition of \cdf{g} were to change
incompatibly could stack-allocate the list argument to \cdf{g} in \cdf{f}.
Other interesting cases are
\begin{lisp} (declaim (inline g)) \\* (defun g (x) (declare (dynamic-extent x))
...) \\* (defun f () (g (list 1 2 3)))
\end{lisp} and
\begin{lisp} (defun f () \\* ~~(flet ((g (x) (declare (dynamic-extent x)) ...))
\\* ~~~~(g (list 1 2 3))))
\end{lisp} In each case some compilers might realize the optimization is
possible and others might not.
An interesting variant of this is the so-called \emph{stack-allocated rest
list}, which can be achieved (in implementations supporting the optimization) by
\begin{lisp} (defun f (\&rest x) \\* ~~(declare (dynamic-extent x)) \\* ~~...)
\end{lisp} Note here that although the initial value of \cdf{x} is not
explicitly present, nevertheless in the usual implementation strategy the
function \cdf{f} is responsible for assembling the list for \cdf{x} from the
passed arguments, so the \cdf{f} function can be optimized by a compiler to
construct a stack-allocated list instead of a heap-allocated list.
Some Common Lisp functions take other functions as arguments; frequently the
argument function is a so-called \emph{downward funarg}, that is, a functional
argument that is passed only downward and whose extent may therefore be dynamic.
\begin{lisp} (flet ((gd (x) (atan (sinh x)))) \\* ~~(declare (dynamic-extent
\#'gd))~~~~~;\textrm{\cdf{mapcar} won't hang on to \cdf{gd}}\\* ~~(mapcar \#'gd
my-list-of-numbers))
\end{lisp}
The following three examples are in error, since in each case the value of
\cdf{x} is used outside of its extent.
\begin{lisp} (length (let ((x (list 1 2 3))) \\* ~~~~~~~~~~(declare
(dynamic-extent x)) \\*
~~~~~~~~~~x))~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Wrong}
\end{lisp} The preceding code is obviously incorrect, because the cons cells
making up the list in \cdf{x} might be deallocated (thanks to the declaration)
before \cdf{length} is called.
\begin{lisp} (length (list (let ((x (list 1 2 3))) \\* ~~~~~~~~~~~~~~~~(declare
(dynamic-extent x)) \\*
~~~~~~~~~~~~~~~~x)))~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Wrong}
\end{lisp} In this second case it is less obvious that the code is incorrect,
because one might argue that the cons cells making up the list in \cdf{x} have
no effect on the result to be computed by \cdf{length}. Nevertheless the code
briefly violates the assertion implied by the declaration and is therefore
incorrect. (It is not difficult to imagine a perfectly sensible implementation
of a garbage collector that might become confused by a cons cell containing a
dangling pointer to a list that was once stack-allocated but then deallocated.)
\begin{lisp} (progn (let ((x (list 1 2 3))) \\* ~~~~~~~~~(declare
(dynamic-extent x)) \\*
~~~~~~~~~x)~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~;\textrm{Wrong} \\*
~~~~~~~(print "Six dollars is your change have a nice day NEXT!"))
\end{lisp} In this third case it is even less obvious that the code is
incorrect, because the value of \cdf{x} returned from the \cdf{let} construct is
discarded right away by the \cdf{progn}. Indeed it is, but ``right away'' isn't
fast enough. The code briefly violates the assertion implied by the declaration
and is therefore incorrect. (If the code is being interpreted, the interpreter
might hang on to the value returned by the \cdf{let} for some time before it is
eventually discarded.)
Here is one last example, one that has little practical import but is
theoretically quite instructive.
\begin{lisp} (dotimes (j 10) \\* ~~(declare (dynamic-extent j)) \\* ~~(setq foo
3)~~~~~~~~~~~~~~~~~~~~~;\textrm{Correct} \\* ~~(setq foo
j))~~~~~~~~~~~~~~~~~~~~;\textrm{Erroneous---but why? (see text)}
\end{lisp} Since \cdf{j} is an integer by the definition of \cdf{dotimes}, but
\cdf{eq} and \cdf{eql} are not necessarily equivalent for integers, what are the
otherwise inaccessible parts of \cdf{j}, which this declaration requires the
body of the \cdf{dotimes} not to ``save''? If the value of \cdf{j} is \cd{3},
and the body does \cd{(setq foo~3)}, is that an error? The answer is no, but
the interesting thing is that it depends on the implementation-dependent
behavior of \cdf{eq} on numbers. In an implementation where \cdf{eq} and
\cdf{eql} are equivalent for \cd{3}, then \cd{3} is not an otherwise
inaccessible part because \cd{(eq~j (+~2~1))} is true, and therefore there is
another way to access the object besides going through \cdf{j}. On the other
hand, in an implementation where \cdf{eq} and \cdf{eql} are not equivalent for
\cd{3}, then the particular \cd{3} that is the value of \cdf{j} is an otherwise
inaccessible part, but any other \cd{3} is not. Thus \cd{(setq foo~3)} is valid
but \cd{(setq foo~j)} is erroneous. Since \cd{(setq foo~j)} is erroneous in
some implementations, it is erroneous in all portable programs, but some other
implementations may not be able to detect the error. (If this conclusion seems
strange, it may help to replace \cd{3} everywhere in the preceding argument with
some obvious bignum such as \cd{375374638837424898243} and to replace \cd{10}
with some even larger bignum.)
The \cdf{dynamic-extent} declaration should be used with great care. It makes