Update of /project/mcclim/cvsroot/mcclim/Doc In directory common-lisp.net:/tmp/cvs-serv10401
Modified Files: manual.tex Log Message: Added new part, "Utility Programs", which covers things like the Listener and Clouseau. The listener chapter is blank, but the Clouseau chapter contains information on how to get started, some tips, and a tutorial on how to extend it.
Date: Thu Mar 10 23:45:56 2005 Author: pscott
Index: mcclim/Doc/manual.tex diff -u mcclim/Doc/manual.tex:1.23 mcclim/Doc/manual.tex:1.24 --- mcclim/Doc/manual.tex:1.23 Tue Dec 28 10:17:07 2004 +++ mcclim/Doc/manual.tex Thu Mar 10 23:45:55 2005 @@ -1488,6 +1488,366 @@
Loads a description of a font from the specified AFM file.
+\part{Utility Programs} + +\chapter{Listener} + +\chapter{Inspector: Clouseau} + +The inspector, called ``Clouseau'', is used for interactively +inspecting objects. It lets you look inside objects, inspect slots, +disassemble and trace functions, view keys and values in hash tables, +and quite a few other things as well. It can be extended to aid in +debugging of specific programs, similar to the way the Lisp printer +can be extended with \genfun{print-object}. + +\section{Usage} + +\subsection{Quick Start} + +To get up and running quickly with Clouseau: + +\begin{enumerate} +\item With ASDF and McCLIM loaded, load the file + + \texttt{mcclim/Apps/Inspector/inspector.asd}. +\item Load Clouseau with: + +\texttt{(asdf:operate 'asdf:load-op :clouseau)} +\item Inspect an object with \texttt{(clouseau:inspector + \textit{object})}. If you use a multithreaded Lisp implementation, + you can also include the \cl{:new-process} keyword argument. If it + is \cl{t}, then Clouseau is started in a seperate process. This + should be relatively safe; it is even possible to have an inspector + inspecting another running inspector. +\end{enumerate} + +\subsection{The Basics} + +Once you inspect something, you will see a full representation of the +object you are inspecting and short representations of objects +contained within it. This short representation may be something like +\cl{#<STANDARD-CLASS SALAD-MIXIN>} or something as short as ``\dots''. +To see these objects inspected more fully, left-click on them and they +will be expanded. To shrink expanded objects, left-click on them again +and they will go back to a brief form. + +That's really all you need to know to get started. The best way to +learn how to use Clouseau is to start inspecting your own objects. + +\subsection{Handling of Specific Data Types} + +Clouseau can handle numerous data types in different ways. Here are +some handy features you might miss if you don't know to look for them: + +\subsubsection{Standard Objects} + +Standard objects have their slots shown, and by left-clicking on the +name of a slot you can change the slot's value. You can see various +slot attributes by middle clicking on a slot name. + +\subsubsection{Structures} + +Structures are inspected the same way as standard objects. + +\subsubsection{Generic Functions} + +You can remove methods from generic functions with the \texttt{Remove +Method} command. + +\subsubsection{Functions} + +You can disassemble functions with the \texttt{Toggle Disassembly} +command. If the disassembly is already shown, this command hides it. + +\subsubsection{Symbols} + +If a symbol is fbound, you can use the \texttt{Trace} and +\texttt{Untrace} commands to trace and untrace the function bound to +it. + +\subsubsection{Lists and Conses} + +Lists and conses can be displayed in either the classic format (such +as \texttt{(1 3 (4 . 6) "Hello" 42)}) or a more graphical cons-cell +diagram format. The default is the classic format, but this can be +toggled with the \texttt{Toggle Show List Cells} command. + +\section{Extending Clouseau} + +Sometimes Clouseau's built-in inspection abilities aren't enough, and +you want to be able to extend it to inspect one of your own classes in +a special way. Clouseau supports this, and it's fairly simple and +straightforward. + +Suppose that you're writing a statistics program and you want to +specialize the inspector for your application. When you're looking at +a sample of some characteristic of a population, you want to be able +to inspect it and see some statistics about it, like the average. This +is easy to do. + +We define a class for a statistical sample. We're keeping this very +basic, so it'll just contain a list of numbers: + +\begin{alltt} +(in-package :clim-user) +(use-package :clouseau) + +(defclass sample () + ((data :initarg :data + :accessor data + :type list :initform '())) + (:documentation "A statistical sample")) + +(defgeneric sample-size (sample) + (:documentation "Return the size of a statistical sample")) + +(defmethod sample-size ((sample sample)) + (length (data sample))) +\end{alltt} + +The \genfun{print-object} function we define will print samples +unreadably, just showing their sample size. For example, a sample with +nine numbers will print as \texttt{#<SAMPLE n=9>} We create such a +sample and call it \cl{*my-sample*}. + +\begin{alltt} +(defmethod print-object ((object sample) stream) + (print-unreadable-object (object stream :type t) + (format stream "n=~D" (sample-size object)))) + +(defparameter *my-sample* + (make-instance 'sample + :data '(12.8 3.7 14.9 15.2 13.66 + 8.97 9.81 7.0 23.092))) +\end{alltt} + +We need some basic statistics functions. First, we'll do sum: + +\begin{alltt} +(defgeneric sum (sample) + (:documentation "The sum of all numbers in a statistical +sample")) + +(defmethod sum ((sample sample)) + (reduce #'+ (data sample))) +\end{alltt} + +Next, we want to be able to compute the mean. This is just the +standard average that everyone learns: add up all the numbers and +divide by how many of them there are. It's written $\overline{x}$. + +\begin{alltt} +(defgeneric mean (sample) + (:documentation "The mean of the numbers in a statistical +sample")) + +(defmethod mean ((sample sample)) + (/ (sum sample) + (sample-size sample))) +\end{alltt} + +Finally, to be really fancy, we'll throw in a function to compute the +standard deviation. You don't need to understand this, but the +standard deviation is a measurement of how spread out or bunched +together the numbers in the sample are. It's written as $\sigma$, and +it's computed like this: + +$$ \sigma = \sqrt{\frac{1}{N} \sum_{i=1}^N (x_i - \overline{x})^2} $$ + +\begin{alltt} +(defgeneric standard-deviation (sample) + (:documentation "Find the standard deviation of the numbers in a +sample. This measures how spread out they are.")) + +(defmethod standard-deviation ((sample sample)) + (let ((mean (mean sample))) + (sqrt (/ (loop for x in (data sample) + sum (expt (- x mean) 2)) + (sample-size sample))))) +\end{alltt} + +This is all very nice, but when we inspect \cl{*my-sample*} all we see +is a distinctly inconvenient display of the class, its superclass, and +its single slot, which we actually need to \emph{click on} to see. In +other words, there's a lot of potential being missed here. How do we +take advantage of it? + +We can define our own inspection functions. To do this, we have two +methods that we can define. To change how sample objects are inspected +compactly, before they are clicked on, we can define an +\genfun{inspect-object-briefly} method for our \cl{sample} class. To +change the full, detailed inspection of samples, we define +\genfun{inspect-object} for the class. Both of these methods take two +arguments: the object to inspect and a CLIM output stream. They are +expected to print a representation of the object to the stream. + +Because we defined \genfun{print-object} for the \cl{sample} class to +be as informative as we want the simple representation to be, we don't +need to define a special \genfun{inspect-object-briefly} method. We +should, however, define \genfun{inspect-object}. + +\begin{alltt} +(defmethod inspect-object ((object sample) pane) + (inspector-table (object pane) + ;; This is the header + (format pane "SAMPLE n=~D" (sample-size object)) + ;; Now the body + (inspector-table-row (pane) + (princ "mean" pane) + (princ (mean object) pane)) + (inspector-table-row (pane) + (princ "std. dev." pane) + (princ (standard-deviation object) pane)))) +\end{alltt} + +Here, we introduce two new macros. \macro{inspector-table} sets up a +box in which we can display our representation of the sample. It +handles quite a bit of CLIM work for us. When possible, you should use +it instead of making your own, since using the standard facilities +helps ensure consistency. + +The second macro, \macro{inspector-table-row}, creates a row with the +output of one form bolded on the left and the output of the other on +the right. This gives us a reasonable output; try it yourself and see. + +% FIXME: SCREENSHOT, and remove ``;try it yourself...'' + +But what we really want is something more closely adapted to our +needs. It would be nice if we could just have a table of things like +$ \overline{x} = 12.125776 $ and have them come out formatted +nicely. Before we attempt mathematical symbols, let's focus on getting +the basic layout right. For this, we can use CLIM's table formatting. + +\begin{alltt} +(defmethod inspect-object ((object sample) pane) + (flet ((x=y (x y) + (formatting-row (pane) + (formatting-cell (pane :align-x :right) + (princ x pane)) + (formatting-cell (pane) (princ "=" pane)) + (formatting-cell (pane) + (inspect-object y pane))))) + (inspector-table (object pane) + ;; This is the header + (format pane "SAMPLE n=~D" (sample-size object)) + ;; Now the body + (x=y "mean" (mean object)) + (x=y "std. dev." (standard-deviation object))))) +\end{alltt} + +In this version, we define a local function \cl{x=y} which outputs a +row showing something in the form ``label = value''. If you look +closely, you'll notice that we print the label with \cl{princ} but we +print the value with \genfun{inspect-object}. This makes the value +inspectable, as it should be. + +Then, in the \macro{inspector-table} body, we insert a couple of calls +to \cl{x=y} and we're done. Have a look and see. %It looks like this: + +% FIXME: SCREENSHOT + +Finally, for our amusement and further practice, we'll try to get some +mathematical symbols. We could get $\sigma$ most easily by using a +Lisp that supports Unicode, but we'll just use the letter S instead. + +\begin{alltt} +(defun xbar (stream) + "Draw an x with a bar over it" + (with-room-for-graphics (stream) + (with-text-face (stream :italic) + (princ #\textbackslash{}x stream) + (draw-line* stream 0 0 + (text-style-width *default-text-style* + stream) 0)))) + +(defmethod inspect-object ((object sample) pane) + (flet ((x=y (x y) + (formatting-row (pane) + (formatting-cell (pane :align-x :right) + ;; Call functions, print everything else in italic + (if (functionp x) + (funcall x pane) + (with-text-face (pane :italic) + (princ x pane)))) + (formatting-cell (pane) (princ "=" pane)) + (formatting-cell (pane) + (inspect-object y pane))))) + (inspector-table (object pane) + ;; This is the header + (format pane "SAMPLE n=~D" (sample-size object)) + ;; Now the body + (x=y #'xbar (mean object)) + (x=y #\textbackslash{}S (standard-deviation object))))) +\end{alltt} + +Finally, to illustrate the proper use of +\genfun{inspect-object-briefly}, suppose that we want the "n=9" (or +whatever the sample size $n$ equals) part to have an itlicised $n$. We +can fix this easily: + +\begin{alltt} +(defmethod inspect-object-briefly ((object sample) pane) + (with-output-as-presentation (pane object 'sample) + (with-text-family (pane :fix) + (print-unreadable-object (object pane :type t) + (with-text-family (pane :serif) + (with-text-face (pane :italic) + (princ "n" pane))) + (format pane "=~D" (sample-size object)))))) +\end{alltt} + +Notice that the body of \genfun{inspect-object-briefly} just prints a +representation to a stream, like \genfun{inspect-object} but shorter. +It should wrap its output in \macro{with-output-as-presentation}. +\genfun{inspect-object} does this too, but it's hidden in the +\macro{inspector-table} macro. + +For more examples of how to extend the inspector, you can look at +\texttt{inspector.lisp}. + +\section{API} + +The following symbols are exported from the \cl{clouseau} package: + +\defun {inspector} {object \key new-process} + +Inspect \cl{object}. If \cl{new-process} is \cl{t}, Clouseau will be +run in a new process. + +\defgeneric {inspect-object} {object pane} + +Display inspected representation of \cl{object} to the extended output +stream \cl{pane}. This requires that \cl{*application-frame*} be bound +to an inspector application frame, so it isn't safe to use in other +applications. + +\defgeneric {inspect-object-briefly} {object pane} + +A brief version of \genfun{inspect-object}. The output should be +short, and should try to fit on one line. + +\defgeneric {define-inspector-command} {name args \rest body} + +This is just an inspector-specific version of +\genfun{define-command}. If you want to define an inspector command +for some reason, use this. + +\defmacro {inspector-table} {(object pane) header \body body} + +Present \cl{object} in tabular form on \cl{pane}, with \cl{header} +evaluated to print a label in a box at the top. \cl{body} should +output the rows of the table, possibly using \cl{inspector-table-row}. + +\defmacro {inspector-table-row} {(pane) left right} + +Output a table row with two items, produced by evaluating \cl{left} +and \cl{right}, on \cl{pane}. This should be used only within +\cl{inspector-table}. + +When possible, you should try to use this and \cl{inspector-table} for +consistency, and because they handle quite a bit of effort for you. + \part{Auxiliary Material}
\chapter{Glossary}