-
Notifications
You must be signed in to change notification settings - Fork 10
/
amop.tex
5105 lines (3840 loc) · 205 KB
/
amop.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
\clearpage\def\pagestatus{FINAL PROOF}
\chapter{Metaobject Protocol}
\label{METAOBJECT-PROTOCOL}
Book: Art Of Metaobject Protocol
Chapters 5,6
Authors: Gregor Kiczales, Jim des Rivieres, and Daniel G. Bobrow
\href{http://www.alu.org/mop/index.html}{http://www.alu.org/mop/index.html}
\section{Concepts}
\subsection{Introduction}
\subsection{Введение}
The CLOS Specification~\ref{CLOS} describes the standard Programmer Interface for the
Common Lisp Object System (CLOS). This document extends that specification by
defining a metaobject protocol for CLOS---that is, a description of CLOS itself
as an extensible CLOS program. In this description, the fundamental elements of
CLOS programs (classes, slot definitions, generic functions, methods,
specializers and method combinations) are represented by first-class
objects. The behavior of CLOS is provided by these objects, or, more precisely,
by methods specialized to the classes of these objects.
Because these objects represent pieces of CLOS programs, and because their
behavior provides the behavior of the CLOS language itself, they are considered
meta-level objects or metaobjects. The protocol followed by the metaobjects to
provide the behavior of CLOS is called the CLOS Metaobject Protocol (MOP).
CLOS спецификация~\ref{CLOS} описывает API для Common Lisp'овой объектной
системы. Данная глава дополняет эту спецификацию описанием метаобъектного
протокола для CLOS --- то. В этом описании, базовые элементы CLOS'а (классы,
определения слотов, обобщённые функции, методы, специализаторы и комбинации
методов) представлены в качестве представлены как объекты первого
класса. Поведение CLOS'а регулируется этими объектами, или, если быть точнее,
методами, специализированным для объектов этих классов.
Так как эти объекты представляют части CLOS программы, и так как их поведение
задаёт поведение языка CLOS, они рассматриваются как объекты метауровня или
метаобъекты. Протокол определения методов для метаобъектов называется
Метаобъектным Протоколом CLOS (на английском MOP).
\subsubsection{Metaobjects}
\subsubsection{Метаобъекты}
For each kind of program element there is a corresponding basic metaobject
class. These are the classes: \cdf{class}, \cdf{slot-definition},
\cdf{generic-function}, \cdf{method}
and \cdf{method-combination}. A metaobject class is a subclass of exactly one of these
classes. The results are undefined if an attempt is made to define a class that
is a subclass of more than one basic metaobject class. A metaobject is an
instance of a metaobject class.
Для каждого элемента CLOS программы существует соответствующий базовый
метаобъектный класс. Все классы: \cdf{class}, \cdf{slot-definition},
\cdf{generic-function}, \cdf{method}
и \cdf{method-combination}. Метаобъектный класс является подклассом только
одного из вышеперечисленных. При попытке определить класс, которые наследует
более одного базового метакласса поведение непресказуемо. Метаобъект является
экземпляром метакласса.
Each metaobject represents one program element. Associated with each metaobject
is the information required to serve its role. This includes information that
might be provided directly in a user interface macro such as \cdf{defclass} or
\cdf{defmethod}. It also includes information computed indirectly from other
metaobjects such as that computed from class inheritance or the full set of
methods associated with a generic function.
Каждый метаобъект представляет один элемент CLOS программы. С каждым
метаобъектом связана информация, которая необходима для выполнения им своей
роли. Она включает информацию, которая может быть предоставлена напрямую в
пользовательский макрос, такой, например, как \cdf{defclass} или
\cdf{defmethod}. Она также включает информацию, вычисляемую ненапрямую от других
метаобъектов, так, например, вычисление информации из иерархии классов или
полного множества методов связанных с обобщённой функцией.
Much of the information associated with a metaobject is in the form of
connections to other metaobjects. This interconnection means that the role of a
metaobject is always based on that of other metaobjects. As an introduction to
this interconnected structure, this section presents a partial enumeration of
the kinds of information associated with each kind of metaobject. More detailed
information is presented later.
Много информации связанной с метаобъектом находится в виде виде связи с другими
метаобъектами. Такая взаимосвязь означает, что роль метаобъекта всегда основана
на других метаобъектах. В качестве введения структуру данных взаимосвязей,
данный раздел предоставляет частичное перечисление типов информации связанной с
каждым типов метаобъектов. Более подробная информация будет предоставлена позже.
\subsubsection{Classes}
\subsubsection{Классы}
A \emph{class metaobject} determines the structure and the default behavior of its
instances. The following information is associated with class metaobjects:
\emph{Классовые метаобъекты} определяют структуру и поведение по-умолчанию для
их экземпляров. С классовыми метаобъектами связана следующая информация:
\begin{itemize}
\item
The name, if there is one, is available as an object.
\item
Имя, если оно существует, доступно как объект.
\item
The direct subclasses, direct superclasses and class precedence list are
available as lists of class metaobjects.
\item
Прямые подклассы, прямые суперклассы и список предшествования классов
доступны как списки классовых метаобъектов.
\item
The slots defined directly in the class are available as a list of direct
slot definition metaobjects. The slots which are accessible in instances of
the class are available as a list of effective slot definition metaobjects.
\item
Слоты прямо определённые в классе доступны как список прямых слотовых
метаобъектов. Слоты, которые доступны в экземплярах класса доступны как
список действительных слотовых метаобъектов. FIXME
\item
The documentation is available as a string or \cdf{nil}.
\item
Документация доступна как строка или \cdf{nil}.
\item
The methods which use the class as a specializer, and the generic functions
associated with those methods are available as lists of method and generic
function metaobjects respectively.
\item
Методы, которые используют класс в качестве специализатора, и обобщённые
функции, связанные с этими методами, доступны как списки методовых или
функциональных метаобъектов соответственно.
\end{itemize}
\subsubsection{Slot Definitions}
\subsubsection{Определения слотов}
A \emph{slot definition metaobject} contains information about the definition of a
slot. There are two kinds of slot definition metaobjects. A direct slot
definition metaobject is used to represent the direct definition of a slot in a
class. This corresponds roughly to the slot specifiers found in \cdf{defclass}
forms. An effective slot definition metaobject is used to represent information,
including inherited information, about a slot which is accessible in instances
of a particular class.
\emph{Слотовый метаобъект} содержит информацию об определении слота. Существуют
два вида этих метаобъектов. Прямой слотовой метаобъект используется для
представления определённых слотов напрямую в классе. Он приблизительно отвечает
за спецификаторы слотов, указанные в формах \cdf{defclass}. Метаобъект
действующего слота отображает информацию, которая включает информацию об
унаследованных свойствах слота, о слотах, которые доступны в экземплярах
отдельно взятого класса.
Associated with each class metaobject is a list of direct slot definition
metaobjects representing the slots defined directly in the class. Also
associated with each class metaobject is a list of effective slot definition
metaobjects representing the set of slots accessible in instances of that
class.
The following information is associated with both direct and effective slot
definitions metaobjects:
\begin{itemize}
\item
The name, allocation, and type are available as forms that could appear in a
\cdf{defclass} form.
\item
The initialization form, if there is one, is available as a form that could
appear in a \cdf{defclass} form. The initialization form together with its lexical
environment is available as a function of no arguments which, when called,
returns the result of evaluating the initialization form in its lexical
environment. This is called the \emph{initfunction} of the slot.
\item
The slot filling initialization arguments are available as a list of
symbols.
\item
The documentation is available as a string or \cdf{nil}.
\end{itemize}
Certain other information is only associated with direct slot definition
metaobjects. This information applies only to the direct definition of the slot
in the class (it is not inherited).
\begin{itemize}
\item
The function names of those generic functions for which there are
automatically generated reader and writer methods. This information is
available as lists of function names. Any accessors specified in the
\cdf{defclass} form are broken down into their equivalent readers and writers in
the direct slot definition.
\end{itemize}
Information, including inherited information, which applies to the definition of
a slot in a particular class in which it is accessible is associated only with
effective slot definition metaobjects.
\begin{itemize}
\item
For certain slots, the location of the slot in instances of the class is
available.
\end{itemize}
\subsubsection{Generic Functions}
A \emph{generic function metaobject} contains information about a generic function over
and above the information associated with each of the generic function's
methods.
\begin{itemize}
\item
The name is available as a function name.
\item
The methods associated with the generic function are available as a list of
method metaobjects.
\item
The default class for this generic function's method metaobjects is
available as a class metaobject.
\item
The lambda list is available as a list.
\item
The method combination is available as a method combination metaobject.
\item
The documentation is available as a string or \cdf{nil}.
\item
The argument precedence order is available as a permutation of those symbols
from the lambda list which name the required arguments of the generic
function.
\item
The declarations are available as a list of declarations.
\textbf{Terminology Note:} There is some ambiguity in Common Lisp about the
terms used to identify the various parts of \cdf{declare} special operators. In this
document, the term \emph{declaration} is used to refer to an object that could be
an argument to a \cdf{declare} special operator. For example, in the special form
\cd{(declare (special *g1*))}, the list \cd{(special *g1*)} is a declaration.
\end{itemize}
\subsubsection{Methods}
A \emph{method metaobject} contains information about a specific method.
\begin{itemize}
\item
The qualifiers are available as a list of of non-null atoms.
\item
The lambda list is available as a list.
\item
The specializers are available as a list of specializer metaobjects.
\item
The function is available as a function. This function can be applied to
arguments and a list of next methods using \emph{apply} or \emph{funcall}.
\item
When the method is associated with a generic function, that generic function
metaobject is available. A method can be associated with at most one generic
function at a time.
\item
The documentation is available as a string or \cdf{nil}.
\end{itemize}
\subsubsection{Specializers}
A \emph{specializer metaobject} represents the specializers of a method. Class
metaobjects are themselves specializer metaobjects. A special kind of
specializer metaobject is used for \emph{eql} specializers.
\subsubsection{Method Combinations}
A \emph{method combination metaobject} represents the information about the method
combination being used by a generic function.
\textbf{Note:} This document does not specify the structure of method
combination metaobjects.
\subsection{Inheritance Structure of Metaobject Classes}
The inheritance structure of the specified metaobject classes is shown in the
table~\ref{MOP-CLASSES}.
\begin{table}[t]
\caption{Direct superclass relationships among the specified metaobject classes}
\label{MOP-CLASSES}
\begin{flushleft}
\cf
\begin{tabular}{@{}ll@{}}
\textbf{Metaobject Class}&\textbf{Direct Superclasses} \\
\hlinesp
standard-object&(t)\\
funcallable-standard-object&(standard-object function)\\
*metaobject&(standard-object)\\
*generic-function&(metaobject funcallable-standard-object)\\
standard-generic-function&(generic-function)\\
*method&(metaobject)\\
standard-method&(method)\\
*standard-accessor-method&(standard-method)\\
standard-reader-method&(standard-accessor-method)\\
standard-writer-method&(standard-accessor-method)\\
*method-combination&(metaobject)\\
*slot-definition&(metaobject)\\
*direct-slot-definition&(slot-definition)\\
*effective-slot-definition&(slot-definition)\\
*standard-slot-definition&(slot-definition)\\
standard-direct-slot-definition&(standard-slot-definition direct-slot-definition)\\
standard-effective-slot-definition&(standard-slot-definition effective-slot-definition)\\
*specializer&(metaobject)\\
eql-specializer&(specializer)\\
*class&(specializer)\\
built-in-class&(class)\\
forward-referenced-class&(class)\\
standard-class&(class)\\
funcallable-standard-class&(class)
\end{tabular}
\end{flushleft}
The class of every class shown is \cdf{standard-class} except for the class
\cdf{t} which is
an instance of the class \cdf{built-in-class} and the classes
\cdf{generic-function} and
\cdf{standard-generic-function} which are instances of the class
\cdf{funcallable-standard-class}.
[Each class marked with a ``*'' is an abstract class and is not intended to be
instantiated. The results are undefined if an attempt is made to make an
instance of one of these classes with \cdf{make-instance}.]
\end{table}
The classes \cdf{standard-class}, \cdf{standard-direct-slot-definition},
\cdf{standard-effective-slot-definition}, \cdf{standard-method},
\cdf{standard-reader-method},
\cdf{standard-writer-method} and \cdf{standard-generic-function} are called
\emph{standard
metaobject classes}. For each kind of metaobject, this is the class the user
interface macros presented in the CLOS Specification use by default. These are
also the classes on which user specializations are normally based.
The classes \cdf{built-in-class}, \cdf{funcallable-standard-class} and
\cdf{forward-referenced-class} are special-purpose class metaobject classes. Built-in
classes are instances of the class \cdf{built-in-class}. The class
\cdf{funcallable-standard-class} provides a special kind of instances described in the
section~\ref{FUNCALLABLE-INSTANCES}. When the definition of a class
references another class which has not yet been defined, an instance of
\cdf{forward-referenced-class} is used as a stand-in until the class is actually
defined.
The class \cdf{standard-object} is the \emph{default direct superclass} of the class
\cdf{standard-class}. When an instance of the class \cdf{standard-class} is
created, and no
direct superclasses are explicitly specified, it defaults to the class
\cdf{standard-object}. In this way, any behavior associated with the class
\cdf{standard-object} will be inherited, directly or indirectly, by all
instances of
the class \cdf{standard-class}. A subclass of \cdf{standard-class} may have a
different
class as its default direct superclass, but that class must be a subclass of the
class \cdf{standard-object}.
The same is true for \cdf{funcallable-standard-class} and
\cdf{funcallable-standard-object}.
The class \cdf{specializer} captures only the most basic behavior of method
specializers, and is not itself intended to be instantiated. The class \cdf{class} is
a direct subclass of \cdf{specializer} reflecting the property that classes by
themselves can be used as method specializers. The class \cdf{eql-specializer} is used
for \cdf{eql} specializers.
\subsubsection{Implementation and User Specialization}
\label{IMPLEMENTATION-AND-USER-SPECIALIZATION}
The purpose of the Metaobject Protocol is to provide users with a powerful
mechanism for extending and customizing the basic behavior of the Common Lisp
Object System. As an object-oriented description of the basic CLOS behavior, the
Metaobject Protocol makes it possible to create these extensions by defining
specialized subclasses of existing metaobject classes.
The Metaobject Protocol provides this capability without interfering with the
implementor's ability to develop high-performance implementations. This balance
between user extensibility and implementor freedom is mediated by placing
explicit restrictions on each. Some of these restrictions are general---they
apply to the entire class graph and the applicability of all methods. These are
presented in this section.
The following additional terminology is used to present these restrictions:
\begin{itemize}
\item
Metaobjects are divided into three categories. Those defined in this
document are called \emph{specified}; those defined by an implementation but not
mentioned in this document are called \emph{implementation-specific}; and those
defined by a portable program are called \emph{portable}.
\item
A class $I$ is \emph{interposed} between two other classes $C_1$ and $C_2$ if and only if
there is some path, following direct superclasses, from the class $C_1$ to the
class $C_2$ which includes $I$.
\item
A method is \emph{specialized} to a class if and only if that class is in the list
of specializers associated with the method; and the method is in the list of
methods associated with some generic function.
\item
In a given implementation, a specified method is said to have been promoted
if and only if the specializers of the method, $S_1 \ldots S_n$, are defined in
this specification as the classes $C_1 \ldots C_n$, but in the implementation, one
or more of the specializers $S_i$, is a superclass of the class given in the
specification $C_i$.
\item
For a given generic function and set of arguments, a method $M_2$ extends a
method $M_1$ if and only if:
\begin{itemize}
\item
(i) $M_1$ and $M_2$ are both associated with the given generic function,
\item
(ii) $M_1$ and $M_2$ are both applicable to the given arguments,
\item
(iii) the specializers and qualifiers of the methods are such that when
the generic function is called, $M_2$ is executed before $M_1$,
\item
(iv) $M_1$ will be executed if and only if \cdf{call-next-method} is invoked from
within the body of $M_2$ and
\item
(v)\cdf{call-next-method} is invoked from within the body of $M_2$, thereby
causing $M_1$ to be executed.
\end{itemize}
\item
For a given generic function and set of arguments, a method $M_2$ overrides a
method $M_1$ if and only if conditions i through iv above hold and
\begin{itemize}
\item
(v') \cdf{call-next-method} is not invoked from within the body of $M_2$, thereby
preventing $M_1$ from being executed.
\end{itemize}
\end{itemize}
\subsubsection{Restrictions on Implementations}
Implementations are allowed latitude to modify the structure of specified
classes and methods. This includes: the interposition of implementation-specific
classes; the promotion of specified methods; and the consolidation of two or
more specified methods into a single method specialized to interposed classes.
Any such modifications are permitted only so long as for any portable class Cp
that is a subclass of one or more specified classes $C_0 \ldots C_i$, the following
conditions are met:
\begin{itemize}
\item
In the actual class precedence list of $C_p$, the classes $C_0 \ldots C_i$ must appear
in the same order as they would have if no implementation-specific
modifications had been made.
\item
The method applicability of any specified generic function must be the same
in terms of behavior as it would have been had no implementation-specific
changes been made. This includes specified generic functions that have had
portable methods added. In this context, the expression ``the same in terms
of behavior'' means that methods with the same behavior as those specified
are applicable, and in the same order.
\item
No portable class $C_p$ may inherit, by virtue of being a direct or indirect
subclass of a specified class, any slot for which the name is a symbol
accessible in the \cdf{common-lisp-user} package or exported by any package
defined in the ANSI Common Lisp standard.
\item
Implementations are free to define implementation-specific before- and
after-methods on specified generic functions. Implementations are also free
to define implementation-specific around-methods with extending behavior.
\end{itemize}
\subsubsection{Restrictions on Portable Programs}
Portable programs are allowed to define subclasses of specified classes, and are
permitted to define methods on specified generic functions, with the following
restrictions. The results are undefined if any of these restrictions is
violated.
\begin{itemize}
\item Portable programs must not redefine any specified classes, generic
functions, methods or method combinations. Any method defined by a portable
program on a specified generic function must have at least one specializer
that is neither a specified class nor an \cdf{eql} specializer whose
associated value is an instance of a specified class.
\item Portable programs may define methods that extend specified methods
unless the description of the specified method explicitly prohibits
this. Unless there is a specific statement to the contrary, these extending
methods must return whatever value was returned by the call to
\cdf{call-next-method}.
\item Portable programs may define methods that override specified methods
only when the description of the specified method explicitly allows
this. Typically, when a method is allowed to be overridden, a small number
of related methods will need to be overridden as well.
\item An example of this is the specified methods on the generic functions
\cdf{add-dependent}, \cdf{remove-dependent} and
\cdf{map-dependents}. Overriding a specified
method on one of these generic functions requires that the corresponding
method on the other two generic functions be overridden as well.
\item Portable methods on specified generic functions specialized to portable
metaobject classes must be defined before any instances of those classes (or
any subclasses) are created, either directly or indirectly by a call to
\cdf{make-instance}. Methods can be defined after instances are created by
\cdf{allocate-instance} however. Portable metaobject classes cannot be
redefined.
\textbf{Implementation Note:} The purpose of this last restriction is to
permit implementations to provide performance optimizations by analyzing, at
the time the first instance of a metaobject class is initialized, what
portable methods will be applicable to it. This can make it possible to
optimize calls to those specified generic functions which would have no
applicable portable methods.
\textbf{Note:} The specification technology used in this document needs
further development. The concepts of object-oriented protocols and subclass
specialization are intuitively familiar to programmers of object-oriented
systems; the protocols presented here fit quite naturally into this
framework. Nonetheless, in preparing this document, we have found it
difficult to give specification-quality descriptions of the protocols in a
way that makes it clear what extensions users can and cannot
write. Object-oriented protocol specification is inherently about specifying
leeway, and this seems difficult using current technology.
\end{itemize}
\subsection{Processing of the User Interface Macros}
A list in which the first element is one of the symbols \cdf{defclass}, \cdf{defmethod},
\cdf{defgeneric}, or \cdf{define-method-combination}, and which has proper syntax for that
macro is called a \emph{user interface macro form}. This document provides an extended
specification of the \cdf{defclass}, \cdf{defmethod} and \cdf{defgeneric} macros.
The user interface macros \cdf{defclass}, \cdf{defgeneric} and \cdf{defmethod} can be used not
only to define metaobjects that are instances of the corresponding standard
metaobject class, but also to define metaobjects that are instances of
appropriate portable metaobject classes. To make it possible for portable
metaobject classes to properly process the information appearing in the macro
form, this document provides a limited specification of the processing of these
macro forms.
User interface macro forms can be \emph{evaluated} or \emph{compiled} and later
\emph{executed}. The
effect of evaluating or executing a user interface macro form is specified in
terms of calls to specified functions and generic functions which provide the
actual behavior of the macro. The arguments received by these functions and
generic functions are derived in a specified way from the macro form.
Converting a user interface macro form into the arguments to the appropriate
functions and generic functions has two major aspects: the conversion of the
macro argument syntax into a form more suitable for later processing, and the
processing of macro arguments which are forms to be evaluated (including method
bodies).
In the syntax of the \cdf{defclass} macro, the \emph{initform} and
\emph{default-initarg-initial-value-form} arguments are forms which will be evaluated
one or more times after the macro form is evaluated or executed. Special
processing must be done on these arguments to ensure that the lexical scope of
the forms is captured properly. This is done by building a function of zero
arguments which, when called, returns the result of evaluating the form in the
proper lexical environment.
In the syntax of the \cdf{defmethod} macro the \emph{form*} argument is a list of forms that
comprise the body of the method definition. This list of forms must be processed
specially to capture the lexical scope of the macro form. In addition, the
lexical functions available only in the body of methods must be introduced. To
allow this and any other special processing (such as slot access optimization),
a specializable protocol is used for processing the body of methods. This is
discussed in the section~\ref{PROCESSING-METHOD-BODIES}.
\subsubsection{Compile-file Processing of the User Interface Macros}
It is common practice for Common Lisp compilers, while processing a file or set
of files, to maintain information about the definitions that have been compiled
so far. Among other things, this makes it possible to ensure that a global macro
definition (\cdf{defmacro} form) which appears in a file will affect uses of the
macro
later in that file. This information about the state of the compilation is
called the \emph{compile-file environment}.
When compiling files containing CLOS definitions, it is useful to maintain
certain additional information in the compile-file environment. This can make it
possible to issue various kinds of warnings (e.g., lambda list congruence) and
to do various performance optimizations that would not otherwise be possible.
At this time, there is such significant variance in the way existing Common Lisp
implementations handle compile-file environments that it would be premature to
specify this mechanism. Consequently, this document specifies only the behavior
of evaluating or executing user interface macro forms. What functions and
generic functions are called during compile-file processing of a user interface
macro form is not specified. Implementations are free to define and document
their own behavior. Users may need to check implementation-specific behavior
before attempting to compile certain portable programs.
\subsubsection{The \cdf{defclass} Macro}
A \cdf{defclass} form with standard slot and class options and an expansion of it that
would result in the proper call to \cdf{ensure-class}.
\begin{lisp}
(defclass plane (moving-object graphics-object)\\*
~~~~~((altitude :initform 0 :accessor plane-altitude)\\*
~~~~~~(speed))\\*
~~(:default-initargs :engine *jet*))\\*
\\
(ensure-class\\*
~~'plane\\*
~~':direct-superclasses\\*
~~'(moving-object graphics-object)\\*
~~':direct-slots (list (list ':name 'altitude\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ':initform '0\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ':initfunction \#'(lambda () 0)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ':readers '(plane-altitude)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ':writers '((setf plane-altitude)))\\*
~~~~~~~~~~~~~~~~~~~~~~ (list ':name 'speed))\\*
~~':direct-default-initargs (list (list ':engine '*jet* \\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\#'(lambda () *jet*))))\\*
\end{lisp}
A \cdf{defclass} form with non-standard class and slot options, and an
expansion of it which results in the proper call to \cdf{ensure-class}.
Note that the order of the slot options has not affected the order of the
properties in the canonicalized slot specification, but has affected the order
of the elements in the lists which are the values of those properties.
\begin{lisp}
(defclass sst (plane)\\*
~~~~ ((mach mag-step 2\\*
~~~~~~~~~~~~locator sst-mach\\*
~~~~~~~~~~~~locator mach-location\\*
~~~~~~~~~~~~:reader mach-speed\\*
~~~~~~~~~~~~:reader mach))\\*
~~(:metaclass faster-class)\\*
~~(another-option foo bar))\\*
\\
(ensure-class 'sst\\*
~~':direct-superclasses\\*
~~'(plane)\\*
~~':direct-slots (list (list ':name 'mach\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ':readers '(mach-speed mach)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'mag-step '2\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 'locator '(sst-mach mach-location)))\\*
~~':metaclass 'faster-class\\*
~~'another-option '(foo bar))\\*
\end{lisp}
The evaluation or execution of a \cdf{defclass} form results in a call to the
ensure-class function. The arguments received by \cdf{ensure-class} are derived from
the \cdf{defclass} form in a defined way. The exact macro-expansion of the \cdf{defclass}
form is not defined, only the relationship between the arguments to the \cdf{defclass}
macro and the arguments received by the \cdf{ensure-class} function. Examples of
typical \cdf{defclass} forms and sample expansions are shown in precedence examples.
\begin{itemize}
\item
The \emph{name} argument to \cdf{defclass} becomes the value of the first argument to
\cdf{ensure-class}. This is the only positional argument accepted by \cdf{ensure-class};
all other arguments are keyword arguments.
\item
The \emph{direct-superclasses} argument to \cdf{defclass} becomes the value of the
\cd{:direct-superclasses} keyword argument to \cdf{ensure-class}.
\item
The \emph{direct slots} argument to \cdf{defclass} becomes the value of the :direct-slots
keyword argument to \cdf{ensure-class}. Special processing of this value is done
to regularize the form of each slot specification and to properly capture
the lexical scope of the initialization forms. This is done by converting
each slot specification to a property list called a \emph{canonicalized slot
specification}. The resulting list of canonicalized slot specifications is
the value of the \cd{:direct-slots} keyword argument.
Canonicalized slot specifications are later used as the keyword arguments to
a generic function which will, in turn, pass them to \cdf{make-instance} for use
as a set of initialization arguments. Each canonicalized slot specification
is formed from the corresponding slot specification as follows:
\begin{itemize}
\item
The name of the slot is the value of the \cd{:name} property. This property
appears in every canonicalized slot specification.
\item
When the \cd{:initform} slot option is present in the slot specification,
then both the \cd{:initform} and \cd{:initfunction} properties are
present in the
canonicalized slot specification. The value of the \cd{:initform} property is
the initialization form. The value of the \cd{:initfunction} property is a
function of zero arguments which, when called, returns the result of
evaluating the initialization form in its proper lexical environment.
\item
If the \cd{:initform} slot option is not present in the slot specification,
then either the \cd{:initfunction} property will not appear, or its value
will be false. In such cases, the value of the \cd{:initform} property, or
whether it appears, is unspecified.
\item
The value of the \cd{:initargs} property is a list of the values of each
\cd{:initarg} slot option. If there are no \cd{:initarg} slot options, then either
the \cd{:initargs} property will not appear or its value will be the empty
list.
\item
The value of the \cd{:readers} property is a list of the values of each
\cd{:reader} and \cd{:accessor} slot option. If there are no
\cd{:reader} or \cd{:accessor}
slot options, then either the \cd{:readers} property will not appear or its
value will be the empty list.
\item
The value of the \cd{:writers} property is a list of the values specified by
each \cd{:writer} and \cd{:accessor} slot option. The value specified by
a \cd{:writer}
slot option is just the value of the slot option. The value specified by
an \cd{:accessor} slot option is a two element list: the first element is the
symbol setf, the second element is the value of the slot option. If
there are no \cd{:writer} or \cd{:accessor} slot options, then either
the \cd{:writers}
property will not appear or its value will be the empty list.
\item
The value of the \cd{:documentation} property is the value of the
\cd{:documentation} slot option. If there is no \cd{:documentation} slot option,
then either the \cd{:documentation} property will not appear or its value
will be false.
\item
All other slot options appear as the values of properties with the same
name as the slot option. Note that this includes not only the remaining
standard slot options (\cd{:allocation} and \cd{:type}), but also any other
options and values appearing in the slot specification. If one of these
slot options appears more than once, the value of the property will be a
list of the specified values.
\item
An implementation is free to add additional properties to the
canonicalized slot specification provided these are not symbols
accessible in the common-lisp-user package, or exported by any package
defined in the ANSI Common Lisp standard.
\end{itemize}
Returning to the correspondence between arguments to the \cdf{defclass} macro and
the arguments received by the \cdf{ensure-class} function:
\item
The \emph{default initargs} class option, if it is present in the \cdf{defclass} form,
becomes the value of the \cd{:direct-default-initargs} keyword argument to
\cdf{ensure-class}. Special processing of this value is done to properly capture
the lexical scope of the default value forms. This is done by converting
each default initarg in the class option into a canonicalized default
initarg. The resulting list of canonicalized default initargs is the value
of the \cd{:direct-default-initargs} keyword argument to \cdf{ensure-class}.
A canonicalized default initarg is a list of three elements. The first
element is the name; the second is the actual form itself; and the third is
a function of zero arguments which, when called, returns the result of
evaluating the default value form in its proper lexical environment.
\item
The \emph{metaclass} class option, if it is present in the \cdf{defclass} form, becomes
the value of the \cd{:metaclass} keyword argument to \cdf{ensure-class}.
\item
The \emph{documentation} class option, if it is present in the \cdf{defclass} form,
becomes the value of the \cd{:documentation} keyword argument to \cdf{ensure-class}.
\item
Any other class options become the value of keyword arguments with the same
name. The value of the keyword argument is the tail of the class option. An
error is signaled if any class option appears more than once in the \cdf{defclass}
form.
\end{itemize}
In the call to \cdf{ensure-class}, every element of its arguments appears in the same
left-to-right order as the corresponding element of the \cdf{defclass} form, except
that the order of the properties of canonicalized slot specifications is
unspecified. The values of properties in canonicalized slot specifications do
follow this ordering requirement. Other ordering relationships in the keyword
arguments to \cdf{ensure-class} are unspecified.
The result of the call to \cdf{ensure-class} is returned as the result of evaluating
or executing the \cdf{defclass} form.
\subsubsection{The \cdf{defmethod} Macro}
The evaluation or execution of a \cdf{defmethod} form requires first that the body of
the method be converted to a method function. This process is described in the
next section. The result of this process is a method function and a set of
additional initialization arguments to be used when creating the new
method. Given these two values, the evaluation or execution of a \cdf{defmethod} form
proceeds in three steps.
The first step ensures the existence of a generic function with the specified
name. This is done by calling the function ensure-generic-function. The first
argument in this call is the generic function name specified in the \cdf{defmethod}
form.
The second step is the creation of the new method metaobject by calling
make-instance. The class of the new method metaobject is determined by calling
\cdf{generic-function-method-class} on the result of the call to
\cdf{ensure-generic-function} from the first step.
The initialization arguments received by the call to \cdf{make-instance} are as
follows:
\begin{itemize}
\item
The value of the \cd{:qualifiers} initialization argument is a list of the
qualifiers which appeared in the \cdf{defmethod} form. No special processing is
done on these values. The order of the elements of this list is the same as
in the \cdf{defmethod} form.
\item
The value of the \cd{:lambda-list} initialization argument is the unspecialized
lambda list from the \cdf{defmethod} form.
\item
The value of the \cd{:specializers} initialization argument is a list of the
specializers for the method. For specializers which are classes, the
specializer is the class metaobject itself. In the case of \cdf{eql} specializers,
it will be an \cdf{eql-specializer} metaobject obtained by calling
\cdf{intern-eql-specializer} on the result of evaluating the \cdf{eql} specializer form
in the lexical environment of the \cdf{defmethod} form.
\item
The value of the \cd{:function} initialization argument is the method function.
\item
The value of the \cd{:declarations} initialization argument is a list of the
declarations from the \cdf{defmethod} form. If there are no declarations in the
macro form, this initialization argument either doesn't appear, or appears
with a value of the empty list.
\item
The value of the \cd{:documentation} initialization argument is the documentation
string from the \cdf{defmethod} form. If there is no documentation string in the
macro form this initialization argument either doesn't appear, or appears
with a value of false.
\item
Any other initialization argument produced in conjunction with the method
function are also included.
\item
The implementation is free to include additional initialization arguments
provided these are not symbols accessible in the \cdf{common-lisp-user}
package,
or exported by any package defined in the ANSI Common Lisp standard.
\end{itemize}
In the third step, \cdf{add-method} is called to add the newly created method to the
set of methods associated with the generic function metaobject.
The result of the call to \cdf{add-method} is returned as the result of evaluating or
executing the \cdf{defmethod} form.
An example \cdf{defmethod} form and one possible correct expansion.
In the expansion, method-lambda is the result of calling \cdf{make-method-lambda} as
described in the section~\ref{PROCESSING-METHOD-BODIES}. The initargs appearing
after :function are assumed to be additional initargs returned from the call to
\cdf{make-method-lambda}.
\begin{figure}
\caption{Example 3}
\label{example-3}
\begin{lisp}
(defmethod move :before ((p position) (l (eql 0))\\*
~~~~~~~~~~~~~~~~~~~~~~~~~\&optional (visiblyp t)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~\&key color)\\*
~~(set-to-origin p)\\*
~~(when visiblyp (show-move p 0 color)))\\*
\\
(let ((\#:g001 (ensure-generic-function 'move)))\\*
~~(add-method \#:g001\\*
~~~~(make-instance (generic-function-method-class \#:g001)\\*
~~~~~~~~~~~~~~~~~~~':qualifiers '(:before)\\*
~~~~~~~~~~~~~~~~~~~':specializers (list (find-class 'position)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~(intern-eql-specializer 0))\\*
~~~~~~~~~~~~~~~~~~~':lambda-list '(p l \&optional (visiblyp t)\\*
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\&key color)\\*
~~~~~~~~~~~~~~~~~~~':function (function~~method-lambda)\\*
~~~~~~~~~~~~~~~~~~~'additional-initarg-1 't\\*
~~~~~~~~~~~~~~~~~~~'additional-initarg-2 '39)))\\*
\end{lisp}
\end{figure}
An example showing a typical \cdf{defmethod} form and a sample expansion is
shown in~\ref{example-3}. The processing of the method body for this method is shown in~\ref{example-4}.
\subsubsection{Processing Method Bodies}
\label{PROCESSING-METHOD-BODIES}
Before a method can be created, the list of forms comprising the method body
must be converted to a method function. This conversion is a two step process.
\textbf{Note:} The body of methods can also appear in the \cd{:initial-methods}
option of \cdf{defgeneric} forms. Initial methods are not considered by any of the
protocols specified in this document.
During macro-expansion of the \cdf{defmethod} macro shown in~\ref{example-3}, code
similar to this would be run to produce the method lambda and additional
initargs. In this example, \emph{environment} is the macroexpansion environment
of the \cdf{defmethod} macro form.
\begin{figure}
\caption{Example 4}
\label{example-4}
\begin{lisp}
(let ((gf (ensure-generic-function 'move)))\\*
~~(make-method-lambda\\*
~~~~gf\\*
~~~~(class-prototype (generic-function-method-class gf))\\*
~~~~'(lambda (p l \&optional (visiblyp t) \&key color)\\*
~~~~~~ (set-to-origin p)\\*
~~~~~~ (when visiblyp (show-move p 0 color)))\\*
~~ environment))\\*
\end{lisp}
\end{figure}
The first step occurs during macro-expansion of the macro form. In this step,
the method lambda list, declarations and body are converted to a lambda
expression called a \emph{method lambda}. This conversion is based on information
associated with the generic function definition in effect at the time the macro
form is expanded.
The generic function definition is obtained by calling
\cdf{ensure-generic-function} with a first argument of the generic function name
specified in the macro form. The \cd{:lambda-list} keyword argument is not
passed in this call.
Given the generic function, production of the method lambda proceeds by calling
make-method-lambda. The first argument in this call is the generic function
obtained as described above. The second argument is the result of calling
\cdf{class-prototype} on the result of calling
\cdf{generic-function-method-class} on the generic function. The third argument
is a lambda expression formed from the method lambda list, declarations and
body. The fourth argument is the macro-expansion environment of the macro form;
this is the value of the \cd{\&environment} argument to the \cdf{defmethod}
macro.
The generic function \cdf{make-method-lambda} returns two values. The first is
the method lambda itself. The second is a list of initialization arguments and
values. These are included in the initialization arguments when the method is
created.
In the second step, the method lambda is converted to a function which properly
captures the lexical scope of the macro form. This is done by having the method
lambda appear in the macro-expansion as the argument of the function special
form. During the subsequent evaluation of the macro-expansion, the result of the
function special operator is the method function.
\subsubsection{The \cdf{defgeneric} Macro}
The evaluation or execution of a \cdf{defgeneric} form results in a call to the
\cdf{ensure-generic-function} function. The arguments received by
\cdf{ensure-generic-function} are derived from the \cdf{defgeneric} form in a defined
way. As with \cdf{defclass} and \cdf{defmethod}, the exact macro-expansion of the \cdf{defgeneric}
form is not defined, only the relationship between the arguments to the macro
and the arguments received by \cdf{ensure-generic-function}.
\begin{itemize}
\item The \emph{function-name} argument to \cdf{defgeneric} becomes the first
argument to ensure-generic-function. This is the only positional argument
accepted by ensure-generic-function; all other arguments are keyword
arguments.
\item The \emph{lambda-list} argument to \cdf{defgeneric} becomes the value of
the :lambda-list keyword argument to ensure-generic-function.