1
2\subsection{Loading and Using}
3The package is loaded using \texttt{load\_package} or
4\texttt{load!-package} in algebraic or symbolic mode, resp. There is a
5central switch \sw{assert}, which is off by default. With
6\sw{assert} off, all type definitions and assertions described
7in the sequel are ignored and have the status of comments. For
8verification of the assertions it most be turned on (dynamically) before
9the first relevant type definition or assertion.
10
11ASSERT aims at the dynamic analysis of RLISP expr procedure in symbolic
12mode. All uses of \texttt{typedef} and \texttt{assert} discussed in the
13following have to take place in symbolic mode. There is, in contrast, a
14final print routine \texttt{assert\_analyze} that is available in both
15symbolic and algebraic mode.
16
17\subsection{Type Definitions}
18Here are some examples for definitions of types:
19\begin{verbatim}
20typedef any;
21typedef number checked by numberp;
22typedef sf checked by sfpx;
23typedef sq checked by sqp;
24\end{verbatim}
25The first one defines a type \texttt{any}, which is not possibly checked
26by any function. This is useful, e.g., for functions which admit any
27argument at one position but at others rely on certain types or
28guarantee certain result types, e.g.,
29\begin{verbatim}
30procedure cellcnt(a);
31   % a is any, returns a number.
32   if not pairp a then 0 else cellcnt car a + cellcnt cdr a + 1;
33\end{verbatim}
34
35The other ones define a type \texttt{number}, which can be checked by
36the RLISP function \texttt{numberp}, a type \texttt{sf} for standard
37forms, which can be checked by the function \texttt{sfpx} provided by
38ASSERT, and similarly a type for standard quotients.
39
40All type checking functions take one argument and return extended
41Boolean, i.e., non-nil iff their argument is of the corresponding type.
42
43\subsection{Assertions}
44Having defined types, we can formulate assertions on expr procedures in
45terms of these types:
46\begin{verbatim}
47assert cellcnt: (any) -> number;
48assert addsq: (sq,sq) -> sq;
49\end{verbatim}
50Note that on the argument side parenthesis are mandatory also with only
51one argument. This notation is inspired by Haskell but avoids the
52intuition of currying.\footnote{This notation has benn suggested by C. Zengler}
53
54Assertions can be dynamically checked only for expr procedures. When
55making assertions for other types of procedures, a warning is issued and
56the assertion has the status of a comment.
57
58It is important that assertions via assert come after the definitions of
59the used types via \texttt{typedef} and also after the definition of the
60procedures they make assertions on.
61
62A natural order for adding type definitions and assertions to the source
63code files would be to have all typedefs at the beginning of a module
64and assertions immediately after the respective functions.
65Fig.~\ref{FIG:assMod} illustrates this. Note that for dynamic checking
66of the assertions the switch \sw{assert} has to be on during
67the translation of the module; i.e., either when reading it with
68\texttt{in} or during compilation. For compilation this can be achieved
69by commenting in the \texttt{on assert} at the beginning or by
70parameterizing the Lisp-specific compilation scripts in a suitable way.
71
72An alternative option is to have type definitions and assertions for
73specific packages right after \texttt{load\_package} in batch files as
74illustrated in Fig.~\ref{FIG:assBat}.
75\begin{figure}
76  \begin{small}
77\begin{verbatim}
78module sizetools;
79
80load!-package 'assert;
81
82% on assert;
83
84typedef any;
85typedef number checked by number;
86
87procedure cellcnt(a);
88   % a is any, returns a number.
89   if not pairp a then 0 else cellcnt car a + cellcnt cdr a + 1;
90
91assert cellcnt: (any) -> number;
92
93% ...
94
95endmodule;
96
97end;  % of file
98\end{verbatim}
99  \end{small}
100  \caption{Assertions in the source code.}\label{FIG:assMod}
101\end{figure}
102
103\begin{figure}
104  \begin{small}
105\begin{verbatim}
106load_package sizetools;
107load_package assert;
108
109on assert;
110
111lisp <<
112   typedef any;
113   typedef number checked by numberp;
114
115   assert cellcnt: (any) -> number
116>>;
117
118% ... computations ...
119
120assert_analyze();
121
122end;  % of file
123\end{verbatim}
124  \end{small}
125  \caption{Assertions in a batch file.}\label{FIG:assBat}
126\end{figure}
127
128\subsection{Dynamic Checking of Assertions}
129Recall that with the switch \sw{assert} off at translation
130time, all type definitions and assertions have the status of comments.
131We are now going to discuss how these statements are processed with
132\sw{assert} on.
133
134\texttt{typedef} marks the type identifier as a valid type and possibly
135associates the given typechecking function with it. Technically, the
136property list of the type identifier is used for both purposes.
137
138\texttt{assert} encapsulates the procedure that it asserts on into
139another one, which checks the types of the arguments and of the result
140to the extent that there are typechecking functions given. Whenever some
141argument does not pass the test by the typechecking function, there is a
142warning message issued. Furthermore, the following numbers are counted
143for each asserted function:
144\begin{enumerate}
145\item The number of overall calls,
146\item the number of calls with at least one assertion violation,
147\item the number of assertion violations.
148\end{enumerate}
149These numbers can be printed anytime in either symbolic or algebraic
150mode using the command \texttt{assert\_analyze()}. This command at the
151same time resets all the counters.
152
153Fig.~\ref{FIG:sample} shows an interactive sample session.
154%
155\begin{figure}
156  \begin{small}
157\begin{verbatim}
1581: symbolic$
159
1602* load_package assert$
161
1623* on assert$
163
1644* typedef sq checked by sqp;
165sqp
166
1675* assert negsq: (sq) -> sq;
168+++ negsq compiled, 13 + 20 bytes
169
170(negsq)
171
1726* assert addsq: (sq,sq) -> sq;
173+++ addsq compiled, 14 + 20 bytes
174
175(addsq)
176
1777* addsq(simp 'x,negsq simp 'y);
178
179((((x . 1) . 1) ((y . 1) . -1)) . 1)
180
1818* addsq(simp 'x,negsq numr simp 'y);
182
183*** assertion negsq: (sq) -> sq violated by arg1 (((y . 1) . 1))
184
185*** assertion negsq: (sq) -> sq violated by result (((y . -1) . -1))
186
187*** assertion addsq: (sq,sq) -> sq violated by arg2 (((y . -1) . -1))
188
189*** assertion addsq: (sq,sq) -> sq violated by result (((y . -1) . -1))
190
191(((y . -1) . -1))
192
1939* assert_analyze()$
194------------------------------------------------------------------------
195function          #calls              #bad calls   #assertion violations
196------------------------------------------------------------------------
197addsq                  2                       1                       2
198negsq                  2                       1                       2
199------------------------------------------------------------------------
200sum                    4                       2                       4
201------------------------------------------------------------------------
202\end{verbatim}
203  \end{small}
204  \caption{An interactive sample session.}\label{FIG:sample}
205\end{figure}
206
207\subsection{Switches}
208\ttindextype{switch}{ASSERT}
209\ttindextype{switch}{ASSERTBREAK}
210\ttindextype{switch}{ASSERTSTATISTICS}
211\hypertarget{switch:ASSERT}{}
212\hypertarget{switch:ASSERTBREAK}{}
213\hypertarget{switch:ASSERTSTATISTICS}{}
214
215As discussed above, the switch \sw{assert} controls at
216translation time whether or not assertions are dynamically checked.
217
218There is a switch \sw{assertbreak}, which is off by default. When
219on, there are not only warnings issued for assertion violations but the
220computations is interrupted with a corresponding error.
221
222The statistical counting of procedure calls and assertion violations is
223toggled by the switch \sw{assertstatistics}, which is on by default.
224
225\subsection{Efficiency}
226The encapsulating functions introduced with assertions are automatically
227compiled.
228
229% sturm@lennier[~/Desktop] time redpsl < taylor.tst > /dev/null
230
231% real	0m0.798s
232% user	0m0.584s
233% sys	0m0.166s
234% sturm@lennier[~/Desktop] time redcsl < taylor.tst > /dev/null
235
236% real	0m1.975s
237% user	0m1.808s
238% sys	0m0.143s
239% sturm@lennier[~/Desktop] time redpsl < taylor.tst > /dev/null
240
241% real	0m0.442s
242% user	0m0.316s
243% sys	0m0.122s
244% sturm@lennier[~/Desktop] time redcsl < taylor.tst > /dev/null
245
246% real	0m0.610s
247% user	0m0.491s
248% sys	0m0.115s
249
250We have experimentally checked assertions on the standard quotient
251arithmetic \texttt{addsq}, \texttt{multsq}, \texttt{quotsq},
252\texttt{invsq}, \texttt{negsq} for the test file \texttt{taylor.tst} of
253the TAYLOR package. For CSL we observe a slowdown of factor 3.2, and for
254PSL we observe a slowdown of factor 1.8 in this particular example,
255where there are 323\,750 function calls checked altogether.
256
257The ASSERT package is considered an analysis and debugging tool.
258Production system should as a rule not run with dynamic assertion
259checking. For critical applications, however, the slowdown might be
260even acceptable.
261
262\subsection{Possible Extensions}
263Our assertions could be used also for a static type analysis of source
264code. In that case, the type checking functions become irrelevant. On
265the other hand, the introduction of variouse unchecked types becomes
266meaningful.
267
268In a model, where the source code is systematically annotated with
269assertions, it is technically no problem to generalize the specification
270of procedure definitions such that assertions become implicit. For
271instance, one could \emph{optionally} admit procedure definitions like
272the following:
273\begin{verbatim}
274procedure cellcnt(a:any):number;
275   if not pairp a then 0 else cellcnt car a + cellcnt cdr a + 1;
276\end{verbatim}
277
278