<h1id="title-non-xs"><ahref="index.html">The Common Lisp Cookbook</a>– LispWorks</h1>
<!-- Announcement we can keep for 1 month or more. I remove it and re-add it from time to time. -->
<pclass="announce">
📹 <ahref="https://www.udemy.com/course/common-lisp-programming/?couponCode=6926D599AA-LISP4ALL">NEW! Learn Lisp in videos and support our contributors with this 40% discount.</a>
</p>
<pclass="announce-neutral">
📕 <ahref="index.html#download-in-epub">Get the EPUB and PDF</a>
</p>
<divid="content"
<p><ahref="http://www.lispworks.com/">LispWorks</a> is a Common Lisp implementation that
comes with its own Integrated Development Environment (IDE) and its share of
unique features, such as the CAPI GUI toolkit. It is <strong>proprietary</strong> and
provides a <strong>free limited version</strong>.</p>
<p>Here, we will mainly explore its IDE, asking ourselves what it can
offer to a seasoned lisper used to Emacs and Slime. The short answer
is: more graphical tools, such as an easy to use graphical stepper, a
tracer, a code coverage browser or again a class browser. Setting and
using breakpoints was easier than on Slime.</p>
<p>LispWorks also provides more integrated tools (the Process browser
lists all processes running in the Lisp image and we can
stop, break or debug them) and presents many information in the form of
graphs (for example, a graph of function calls or a graph of all the
created windows).</p>
<p><imgsrc="assets/lispworks/two-sided-view.png"alt="LispWorks' listener and editor in the Mate desktop environment"title="The LispWorks listener an the editor in the Mate desktop environment"/></p>
<p>We can see a matrix of LispWorks features by edition and platform here: <ahref="http://www.lispworks.com/products/features.html">http://www.lispworks.com/products/features.html</a>.</p>
<p>We highlight:</p>
<ul>
<li>32-bit, 64-bit and ARM support on Windows, MacOS, Linux, Solaris, FreeBSD,</li>
<li><ahref="http://www.lispworks.com/documentation/lw61/CAPRM/html/capiref.htm">CAPI portable GUI toolkit</a>: provides native look-and-feel on Windows, Cocoa, GTK+ and Motif.
<ul>
<li>comes with a graphical “Interface Builder” (think QtCreator) (though not available on MacOS (nor on mobile))</li>
</ul>
</li>
<li><ahref="http://www.lispworks.com/products/lw4mr.html">LispWorks for mobile runtime</a>, for Android and iOS,</li>
<li>optimized application delivery: LispWorks can use a tree shaker to
remove unused lisp code from the delivered applicatiion, thus
shipping lighter binaries than existing open-source implementations.</li>
<li>ability to deliver a dynamic library,</li>
<li>a <ahref="http://www.lispworks.com/documentation/lw71/LW/html/lw-113.htm">Java interface</a>, allowing to call from Lisp to Java or the other way around,</li>
<li>an Objective-C and Cocoa interface, with drag and drop and multi-touch support,</li>
<li>a Foreign Language Interface,</li>
<li>TCP/UDP sockets with SSL & IPv6 support,</li>
<li>natived threads and symmetric multiprocessing, unicode support, and all other Common Lisp features, and all other LispWorks Enterprise features.</li>
</ul>
<p>And, of course, a built-in IDE.</p>
<p>LispWorks is used in diverse areas of the industry. They maintain <ahref="http://www.lispworks.com/success-stories/index.html">a list of success stories</a>. As for software that we can use ourselves, we find <ahref="https://scorecloud.com/">ScoreCloud</a> amazing (a music notation software: you play an instrument, sing or whistle and it writes the music) or <ahref="https://github.com/openmusic-project/openmusic/">OpenMusic</a> (opensource composition environment).</p>
<p>There is a <strong>time limit of 5 hours</strong> for each session, after which LispWorks Personal exits, possibly without saving your work or performing cleanups such as removing temporary files. You are warned after 4 hours of use.</p>
</li>
<li>
<p>It is <strong>impossible to build a binary</strong>. Indeed, the functions <ahref="http://www.lispworks.com/documentation/lw71/LW/html/lw-95.htm">save-image</a>, <ahref="http://www.lispworks.com/documentation/lw71/DV/html/delivery-4.htm#pgfId-852223">deliver</a> (<em>the</em> function to create a stand-alone executable), and load-all-patches are not available.</p>
</li>
<li>
<p><strong>Initialization files are not loaded</strong>. If you are used to initializing Quicklisp from your <code>~/.sbclrc</code> on Emacs, you’ll have to load an init file manually every time you start LispWorks (<code>(load #p"~/.your-init-file</code>)).</p>
</li>
</ul>
<p>For the record, the snippet provided by Quicklisp to put in one’s startup file is the following:</p>
<pre><codeclass="language-lisp">;; provided you installed quicklisp in ~/quicklisp/
<p>You’ll have to paste it to the listener window (with the <code>C-y</code> key, y as “yank”).</p>
<ul>
<li>Layered products that are part of LispWorks Professional and Enterprise Editions (CLIM, KnowledgeWorks, Common SQL and LispWorks ORB) are not included. But <strong>we can try the CAPI toolkit</strong>.</li>
</ul>
<p>The installation process requires you to fill an HTML form to receive
a download link, then to run a first script that makes you accept the
terms and the licence, then to run a second script that installs the software.</p>
<h3id="licencing-model">Licencing model</h3>
<p>LispWorks actually comes in four paid editions. It’s all explained by themselves here: <ahref="http://www.lispworks.com/products/lispworks.html">http://www.lispworks.com/products/lispworks.html</a>. In short, there is:</p>
<ul>
<li>a Hobbyist edition with <code>save-image</code> and <code>load-all-patches</code>, to apply updates of minor versions, without the obvious limitations, for non-commercial and non-academic use,</li>
<li>a HobbyistDV edition with the <code>deliver</code> function to create executables (still for non-commercial and non-academic uses),</li>
<li>a Professional edition, with the <code>deliver</code> function, for commercial and academic uses,</li>
<li>an Enterprise one, with their enterprise modules: the Common SQL interface, LispWorks ORB, KnowledgeWorks.</li>
</ul>
<p>At the time of writing, the licence of the hobbyist edition costs 750 USD, the pro version the double. They are bought for a LW version, per platform. They have no limit of time.</p>
<divclass="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> Please double check their upstream resources and don't hesitate to contact them.
</div>
<h2id="lispworks-ide">LispWorks IDE</h2>
<p>The LispWorks IDE is self-contained, but it is also possible to use LispWorks-the-implementation from Emacs and Slime (see below). The IDE runs <em>inside</em> the Common Lisp image, unlike Emacs which is an external program that communicates with the Lisp image through Swank and Slime. User code runs in the same process.</p>
<h3id="the-editor">The editor</h3>
<p>The editor offers what’s expected: a TAB-completion pop-up, syntax
highlighting, Emacs-like keybindings (including the <code>M-x</code> extended
command). The menus help the discovery.</p>
<p>We personally found the editing experience a bit “raw”. For example:</p>
<ul>
<li>indention after a new line is not automatic, one has to press TAB
again.</li>
<li>the auto-completion is not fuzzy.</li>
<li>there are no plugins similar to <del>Paredit</del> (there is a brand new (2021) <ahref="https://github.com/g000001/lw-paredit">Paredit for LispWorks</a>) or Lispy, nor a Vim layer.</li>
</ul>
<p>We also had an issue, in that the go-to-source function bound to <code>M-.</code>
did not work out for built-in Lisp symbols. Apparently, LispWorks
doesn’t provide much source code, and mostly code of the editor. Some
other commercial Lisps, like Allegro CL, provide more source code</p>
<p>The editor provides an interesting tab: Changed Definitions. It lists the functions and methods that were redefined since, at our choosing: the first edit of the session, the last save, the last compile.</p>
<p>See also:</p>
<ul>
<li>the <ahref="http://www.lispworks.com/documentation/lw71/EDUG-U/html/eduser-u.htm">Editor User Guide</a>.</li>
</ul>
<h3id="keybindings">Keybindings</h3>
<p>Most of the keybindings are similar to Emacs, but not all. Here are some differences:</p>
<ul>
<li>to <strong>compile a function</strong>, use <code>C-S-c</code> (control, shift and c), instead of C-c C-c.</li>
<li>to <strong>compile the current buffer</strong>, use <code>C-S-b</code> (instead of C-c C-k).</li>
</ul>
<p>Similar ones include:</p>
<ul>
<li><code>C-g</code> to cancel what you’re doing,</li>
<li><code>C-x C-s</code> to save the current buffer,</li>
<li><code>M-w</code> and <code>C-y</code> to copy and paste,</li>
<li><code>M-b</code>, <code>M-f</code>, <code>C-a</code>, <code>C-e</code>… to move around words, to go to the beginning or the end of the line,</li>
<li><code>C-k</code> to kill until the end of the line, <code>C-w</code> to kill a selected region,</li>
<li><code>M-.</code> to find the source of a symbol,</li>
<li><code>C-x C-e</code> to evaluate the current defun,</li>
<li>…</li>
</ul>
<p>Some useful functions don’t have a keybinding by default, for example:</p>
<!--- delete selected text with `M-x delete-region` (or kill the region with `C-w`) -->
<ul>
<li>clear the REPL with <code>M-x Clear Listener</code></li>
<li><code>Backward Kill Line</code></li>
</ul>
<p>It is possible to use <strong>classical keybindings</strong>, à la KDE/Gnome. Go to the
Preferences menu, Environment and in the Emulation tab.</p>
<p>There is <strong>no Vim layer</strong>.</p>
<h3id="searching-keybindings-by-name">Searching keybindings by name</h3>
<p>It is possible to search for a keybinding associated to a function, or
a function name from its keybinding, with the menu (Help -> Editing ->
Key to Command / Command to Key) or with <code>C-h</code> followed by a key,
as in Emacs. For example type <code>C-h k</code> then enter a keybinding to
get the command name. See more with <code>C-h ?</code>.</p>
<h3id="tweaking-the-ide">Tweaking the IDE</h3>
<p>It is possible to change keybindings. The editor’s state is accessible
from the <code>editor</code> package, and the editor is built with the CAPI
framework, so we can use the <code>capi</code> interface too. Useful functions
include:</p>
<pre><codeclass="language-lisp">`
editor:bind-key
editor:defcommand
editor:current-point
editor:with-point ;; save point location
editor:move-point
editor:*buffer-list*
editor:*in-listener* ;; returns T when we are in the REPL
…
</code></pre>
<p>Here’s how you can bind keys:</p>
<pre><codeclass="language-lisp">;; Indent new lines.
;; By default, the point is not indented after a Return.
(editor:bind-key "Indent New Line" #\Return :mode "Lisp")
;; Insert pairs.
(editor:bind-key "Insert Parentheses For Selection" #\( :mode "Lisp") ;;
(editor:bind-key "Insert Double Quotes For Selection" #\" :mode "Lisp")
</code></pre>
<p>Here’s how to define a new command. We make the <code>)</code> key
to go past the next closing parenthesis.</p>
<pre><codeclass="language-lisp">(editor:defcommand "Move Over ()" (p)
"Move past the next close parenthesis.
Any indentation preceeding the parenthesis is deleted."
<li>a list of LispWork keybindings: <ahref="https://www.nicklevine.org/declarative/lectures/additional/key-binds.html">https://www.nicklevine.org/declarative/lectures/additional/key-binds.html</a></li>
</ul>
<h3id="the-listener">The listener</h3>
<p>The listener is the REPL we are expecting to find, but it has a slight
difference from Slime.</p>
<p>It doesn’t evaluate the input line by line or form by form, instead it
parses the input while typing. So we get some errors instantly. For
example, we type <code>(abc</code>. So far so good. Once we type a colon to get
<code>(abc:</code>, an error message is printed just above our input:</p>
<pre><code>Error while reading: Reader cannot find package ABC.
CL-USER 1 > (abc:
</code></pre>
<p>Indeed, now <code>abc:</code> references a package, but such a package doesn’t exist.</p>
<p>Its interactive debugger is primarily textual but you can also
interact with it with graphical elements. For example, you can use the
Abort button of the menu bar, which brings you back to the top
level. You can invoke the graphical debugger to see the stacktraces
and interact with them. See the Debugger button at the very end of the
<p>The <ahref="http://www.lispworks.com/documentation/lw61/IDE-W/html/ide-w-496.htm">stepper</a> is one
of the areas where LispWorks shines.</p>
<p>When your are writing code in the editor window, you can set
breakpoints with the big red “Breakpoint” button (or by calling <code>M-x Stepper Breakpoint</code>).
This puts a red mark in your code.</p>
<p>The next time your code is executed, you’ll get a comprehensive Stepper pop-up window showing:</p>
<ul>
<li>your source code, with an indicator showing what expression is being evaluated</li>
<li>a lower pane with two tabs:
<ul>
<li>the backtrace, showing the intermediate variables, thus showing their evolution during the execution of the program</li>
<li>the listener, in the context of this function call, where you can evaluate expressions</li>
</ul>
</li>
<li>and the menu bar with the stepper controls: you can step into the next expression, step on the next function call, continue execution until the position of the cursor, continue the execution until the next breakpoint, etc.</li>
<p>That’s not all. The non-visual, REPL-oriented stepper is also nice. It shows the forms that are being evaluated and their results.</p>
<p>In this example, we use <code>:s</code> to “step” though the current form and its subforms. We are using the usual listener, we can write any Lisp code after the prompt (the little ` -> ` here), and we have access to the local variables (<code>X</code>).</p>
<pre><codeclass="language-lisp">CL-USER 4 > (defun my-abs (x) (cond ((> x 0) x) ((< x 0) (- x)) (t 0)))
CL-USER 5 > (step (my-abs -5))
(MY-ABS -5) -> :s
-5 -> :s
-5
(COND ((> X 0) X) ((< X 0) (- X)) (T 0)) <=> (IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0)))
;; Access to the local variables:
(IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0))) -> (format t "Is X equal to -5? ~a~&" (if (equal x -5) "yes" "no"))
Is X equal to -5? yes
(IF (> X 0) (PROGN X) (IF (< X 0) (- X) (PROGN 0))) -> :s
(> X 0) -> :s
X -> :s
-5
0 -> :s
0
NIL
(IF (< X 0) (- X) (PROGN 0)) -> :s
(< X 0) -> :s
X -> :s
-5
0 -> :s
0
T
(- X) -> :s
X -> :s
-5
5
5
5
5
</code></pre>
<p>Here are the available stepper commands (see <code>:?</code>):</p>
<pre><code>:s Step this form and all of its subforms (optional +ve integer arg)
:st Step this form without stepping its subforms
:si Step this form without stepping its arguments if it is a function call
:su Step up out of this form without stepping its subforms
<li>the <strong>class hierarchy</strong>, showing the superclasses on the left and the subclasses on the right, with their description to the bottom,</li>
<li>the <strong>superclasses viewer</strong>, in the form of a simple schema, and the same for subclasses,</li>
<li>the <strong>slots pane</strong> (the default),</li>
<li>the available <strong>initargs</strong>,</li>
<li>the existing <strong>generic functions</strong> for that class</li>
<li>and the <strong>class precedence list</strong>.</li>
</ul>
<p>The Functions pane lists all methods applicable to that class, so we can discover public methods provided by the CLOS object system: <code>initialize-instance</code>, <code>print-object</code>, <code>shared-initialize</code>, etc. We can double-click on them to go to their source. We can choose not to include the inherited methods too (see the “include inherited” checkbox).</p>
<p>You’ll find buttons on the toolbar (for example, Inspect a generic
function) and more actions on the Methods menu, such as a way to see
the <strong>functions calls</strong>, a menu to <strong>undefine</strong> or <strong>trace</strong> a function.</p>
<p>See more:</p>
<ul>
<li><ahref="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-55.htm#pgfId-871798">Chapter 8 of the documentation: the Class Browser</a></li>
</ul>
<h3id="the-function-call-browser">The function call browser</h3>
<p>The function call browser allows us to see a graph of the callers and
the callees of a function. It provides several ways to filter the
displayed information and to further inspect the call stack.</p>
<divclass="info-box info">
<!-- if inside a <p> then bootstrap adds 10px padding to the bottom -->
<strong>NB:</strong> The Slime functions to find such cross-references are <code>slime-who-[calls, references, binds, sets, depends-on, specializes, macroexpands]</code>.
</div>
<p>After loading a couple packages, here’s a simple example showing who calls the <code>string-trim</code> function.</p>
<p><imgsrc="assets/lispworks/function-call-browser.png"alt="The function call browser"/></p>
<p>It shows functions from all packages, but there is a select box to restrict it further, for example to the “current and used” or only to the current packages.</p>
<p>Double click on a function shown in the graph to go to its source. Again, as in many LispWorks views, the Function menu allows to further manipulate selected functions: trace, undefine, listen (paste the object to the Listener)…</p>
<p>The Text tab shows the same information, but textually, the callers and callees side by side.</p>
<p>We can see cross references for compiled code, and we must ensure the feature is on. When we compile code, LispWorks shows a compilation output likes this:</p>
<p>We see that cross referencing is on. Otherwise, activate it with <code>(toggle-source-debugging t)</code>.</p>
<p>See more:</p>
<ul>
<li><ahref="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-114.htm#pgfId-852601">Chapter 15: the function call browser</a></li>
</ul>
<h3id="the-process-browser">The Process Browser</h3>
<p>The Process Browser shows us a list of all threads running. The input area allows to filter by name. It accepts regular expressions. Then we can stop, inspect, listen, break into these processes.</p>
<p><imgsrc="assets/lispworks/process-browser.png"alt=""The process browser""/></p>
<p>See more:</p>
<ul>
<li><ahref="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u-178.htm#pgfId-852666">Chapter 28: the Process Browser</a></li>
</ul>
<h3id="misc">Misc</h3>
<p>We like the <code>Search Files</code> functionality. It is like a recursive
<code>grep</code>, but we get a typical LispWorks graphical window
that displays the results, allows to double-click on them and that offers
some more actions.</p>
<p>Last but not least, have a look at the <strong>compilation conditions
browser</strong>. LispWorks puts all warnings and errors into a special
browser when we compile a system. From now on we can work on fixing
them and see them disappear from the browser. That helps keeping track
of warnings and errors during development.</p>
<h2id="using-lispworks-from-emacs-and-slime">Using LispWorks from Emacs and Slime</h2>
<p>To do that, you have two possibilities. The first one is to start LispWorks normally, start a Swank server and connect to it from Emacs (Swank is the backend part of Slime).</p>
<li><ahref="http://www.lispworks.com/documentation/lw71/IDE-U/html/ide-u.htm">LispWorks IDE User Guide</a> (check out the sections we didn’t cover)</li>
<li><ahref="https://en.wikipedia.org/wiki/LispWorks">LispWorks on Wikipedia</a></li>