Planet Lisp

Vsevolod DyomkinAnnouncing SHOULD-TEST

· 6 days ago

Once upon a time, it occurred to me that all sound software should be slightly self-ironic. That is how this library's name came into being: yes, you should test even Common Lisp code sometimes. :) But that's not the whole irony...

So, y u makes YATF?

Testing software always fascinated me because it is both almost always necessary and at the same time almost always excessive - it's extremely hard to find the right amount of resources you should allocate to it. You will most likely end up fearing to change your system either because you have too few tests, and some of the important scenarios aren't covered, or too many tests and you need to be constantly re-writing them. Surely, in Lisp the problem is not so drastic because in many cases you can rely on the REPL to help, but it's not a one-fit-all solution. There's also too much dogma in the space of general error handling in programming (that I addressed a little bit in this post). So, to find out how to test properly, around 7 years ago I had written my first test framework, which was called NUTS (non-unit test suite). It worked ok, and I used it in a couple of projects including the huge test suite of CL-REDIS that I'm really proud of. However, it was the first version, and you always have to re-write the first version. :) This is how MUTEST (microtest) appeared. In it, I was aiming at making a tool with the smallest footprint possible. It was also partially inspired by RT, which I consider to be the simplest (with a positive connotation) Lisp test framework (before ST). But both of them, MUTEST and RT, are not lispy because they are not extensible, and it's a shame to not have extensibility in Lisp, which provides excellent tools for building it in.

Well, "version 2 always sucks, but version 3..." So, SHOULD-TEST is version 3, and I'm really happy with it. It's truly minimal and intuitive to the extreme: like in the popular BDD approach you just write (in Yodaspeak, obviously): should be = 1 this-stuff and then st:test. And it's extensible - you can add specialized assertion strategies to the provided 3 basic ones: normal testing, exception catching, and capturing output streams.

I wasn't content with the existing Lisp test frameworks because they aren't concerned first and foremost with the things I care about:

  • intuitive defining and running arbitrary tests
  • testing from the REPL and ease of analyzing the test output
  • piping the test output to upstream systems like CI (by supporting common protocols, such as xUnit and TAP)

These are the 3 things that SHOULD-TEST should do the best.

Over more than a year, I have written or re-written with it the whole test suites for the main open-source libraries I support - RUTILS, CL-REDIS, and CL-NLP (which doesn't yet have an extensive test coverage). And I also use it for all my in-house projects.

Working with ST

Here's a quick overview of the SHOULD-TEST workflow.

Test are defined with deftest:

(deftest some-fn ()
(should be = 1 (some-fn 2))
(should be = 2 (some-fn 1)))

Being run, the defined test returns either T or NIL as a primary value. Secondary and third values in case of NIL are lists of:

  • all failed assertions returned by individual assertions
  • and all uncaught errors signaled inside assertions

should is a macro that takes care of checking assertions. If the assertion doesn't hold should signals a condition of types should-failed or should-erred which are aggregated by deftest. Also, should returns either T or NIL and a list of a failed expression with expected and actual outputs as values.

Under the hood, should calls the generic function should-check and passes it a keyword produced from the first symbol (in this case, :be), a test predicate (here, '=), and a tested expression as thunk (here it will be e.g. (lambda () (some-fn 1))), and expected results if any. If multiple expected results are given, like in (should be eql nil #{:failed 1} (some-other-fn :dummy)), it means that multiple values are expected. As you see, the keyword and test predicate are passed unevaluated, so you can't use expressions here.

The pre-defined types of assertions are be, signal, and print-to. They check correspondingly.

deftest and should write the summary of test results to *test-output* (by default bound to *standard-output*). The var *verbose* (default T) controls if the summary contains full failure reports or just test names.

Tests are defined as lambda-functions attached to a symbol's test property, so (deftest some-fn ... will do the following:

(setf (get some-fn 'test)
(lambda () ...))
One feature that is pending implementation is establishing dependencies between tests while defining them, i.e. specifying the partial order in which they should be run. However, I haven't seen heavy demand for it in my test code so far.

To run the tests, use test. Without arguments, it runs all the tests in the current package. Given a :package argument it will do the same for that package, and given a :test argument it will run that individual test. In case of individual test's failure, it will return NIL and a list of failed assertions and a list of assertions, which triggered uncaught errors. In case of failed test of a package, it will return NIL and 2 hash-tables holding the same lists as above keyed by failed test's names.

As you see, the system uses a somewhat recursive protocol for test results:

  • at the lowest level should returns T or NIL and signals information about the failed assertion
  • this information is aggregated by deftest which will return aggregate information about all the failed assertions in the hash-table
  • at the highest level test will once again aggregate information over all tests

So, the structure of the summary, returned from test, will be the following:

failed-test-1 ((failed-assertion-1 expected actual)
(failed-assertion-2 ...
failed-test-2 ...

There's also :failed key to test that will re-test only tests which failed at their last run.

Usage patterns

As SHOULD-TEST is agnostic, it doesn't impose any restrictions on how each project organizes its tests. Yet, having established patterns and best-practices never hearts. Below is the approach I use...

There's no restriction on naming tests. Though, it seems like a good approach to name them the same as functions they test. As for generic functions, I have different tests for different methods. In this case, I add some suffix to the test's name to indicate which method is tested (like transform-string for one of the methods of gf transform that is specialized for the string class of arguments).

As for code organization, I use the following directory structure of the typical project:

| `----module
| `-----file.lisp

I also usually place the tests in the same package as the code they test but protect them with #+dev guard, so that in production environment they are not compiled and loaded altogether.

ASDF provides a way to define the standard for testing a system that can be invoked with asdf:test-system. The easiest way to hook into this facility is to define the following method for asdf:test-op somewhere either in package.lisp or in some common file in the test module (in the example above: some-general-tests.lisp):

(defmethod asdf:perform ((o asdf:test-op)
(s (eql (asdf:find-system <your-system>))))
(asdf:load-system <your-system>)
(st:test :package <your-package>))

There's also a minimal test suite defined in src/self-test.lisp. The test suite is also hooked to asdf:test-op for the should-test system - just as described above :)
Finally, there's an idea that ST will provide useful connector facilities that are mostly lacking in the existing Lisp test frameworks, to be able to integrate into the general testing landscape (primarily, CI systems). As a start, xUnit support was implemented by us (most of the thanks go to Maxim Zholoback). As it often happens, it was, actually, almost impossible to find the proper xUnit spec, but this SO answer saved the day for us. test-for-xunit generates appropriate XML string to *test-output*. I also plan on implementing TAP support some day (this should be pretty easy, actually), but I'm not in a hurry.

Well, if SHOULD-TEST proves useful to some of you, I'd be glad. Enjoy the hacking!

François-René RideauCommon Lisp as a Scripting Language, 2015 edition

· 7 days ago

The first computer I used had about 2KB of RAM. The other day, I compiled a 2KB Common Lisp script into a 16MB executable to get its startup (and total execution) time down from 2s to subjectively instantaneous — and that didn't bother me the least, for my current computer has 8GB of working memory and over 100GB of persistent memory. But it did bother me that it didn't bother me, for 16MB was also the memory on the first computer in which I felt I wasn't RAM-starved: I could run an X server, an Emacs editor and a shell terminal simultaneously without swapping! Now an entire comfortable software development universe could be casually wasted over a stupid optimization — that I have to care about because software systems still suck. And to imagine that before sentientkind reaches its malthusian future, code bumming will have become a popular activity again...

Background (skip to the next paragraph if you don't care for hardware war stories): I just returned my many-years old work laptop (a Lenovo Thinkpad X230), because of various hardware issues I was starting to experience: mostly a bad connection with the batteries at times causing the machine to shutdown at the least auspicious moment, in addition to the traditional overheating and the wifi card that often failed to connect requiring the wpa_supplicant daemon to be killed. I liked the Thinkpad form factor a lot, but my employer wasn't offering Thinkpad-s anymore, so I opted instead for a slim HP EliteBook Folio 1040, the form factor is obviously inspired from the macbook air, except it was running a Linux system whereby I was master of my ship. Now, the EliteBook has a touchpad that is particularly bad, even worse than the Thinkpad's in being triggered all the time by my thumb as I type; I decided to disable it immediately, just like I did eventually with the Thinkpad; however, unlike the Thinkpad, the EliteBook doesn't have a "clit" interface to supplement the touchpad. Therefore I had to toggle the touchpad on and off instead of permanently disabling it. A Google search quickly found a shell script to toggle the touchpad, and instructions on how to map Penguin-Space to it (the Penguin is Super, much more so than the Windows it replaces). But the shell script frankly made me puke, and I decided to rewrite it in Lisp, which yielded a very nice program less than 2KB long...

Indeed for several years now, I've been peddling the use of Common Lisp as a scripting language: the combination of syntactic abstraction, higher-order functions and an advanced object system, the relatively simple semantic model allowing for efficient compilation, the robust compilers with decent performance and portability to all platforms that matter, and the support for interactive debugging and structured editing — all put it years ahead of all the other dynamically typed scripting languages in common use (shell, perl, python, ruby, javascript), even though it was initially developed years or decades before them. However, until recently, it was missing a few bits to be usable as a scripting language, and I am proud of having hammered the last few nails on the coffin: zero-configuration in looking for source libraries, zero-management in storing compiled outputs, portable invocation from other programs, portable invocation of other program — if you implement these, you too can make your favorite programming language suitable for "scripting".

Well, I recently added an extra nail to the coffin, that addresses the remaining tradeoff between startup times and memory occupancy: it is now possible to easily share a dumped image between all the scripts you need, to achieve instant startup without massive bloat of either working memory or persistent storage. Admittedly, you could already do it semi-portably on SBCL and CCL using Xach's buildapp; but now you can do it fully portably on all implementations using the cl-launch utility that you would use to invoke the program as a script.

The portable way to write a Common Lisp script is to use cl-launch, typically via a #!/usr/bin/cl script specification line when you're using Unix. However, when launching a script this way, even a relatively simple program can take one to several seconds to start: the Lisp compiler locates and loads all the object files into memory, linking the code into symbol, class and method tables; and this somehow takes a non-negligible amount of time even when the files were precompiled, because compilers were never optimized to make this fast;r indeed the typical Lisp hacker only recompiles and reloads one file at a time at his interactive REPL, and doesn't often reload all the files from scratch. By installing ASDF 3.1.4 over the one provided by SBCL using the provided install-asdf.lisp script, and by using the provided cl-source-registry-cache.lisp script to avoid search through my quite large collection of CL source code, I could get the startup time down to around .7 or .8s, but that was still too much. This is fine for computation-intensive and/or long-running programs for which this startup latency doesn't matter. But that makes this solution totally impractical for interactive scripts where execution latency is all-important, as compared to other scripting languages, that while inferior as languages, at least start up instantaneously in subjective time.

/bin/sh or perl execute an empty command in about 5 ms of wall clock time, python in about 18ms (all timing and sizes rough averages and estimates on my current linux x86-64 laptop). Without my portability infrastructure, you can also do the same with sbcl in 10 ms or clisp in 15 ms, but then you lose the portability and are either restricted to not using any software library, or are back in non-portable configuration and compilation hell in addition to having the same slow loading issue. With such startup pause, Common Lisp might remain somewhat suitable to scripting, unlike the vast majority of compiled programming languages, that require a explicit compilation step with non-trivial configuration of source and object files; still it finds itself unsuitable for producing scripts destined for use as instantaneous interactive commands outside its own autistic interactive development environment.

Now, all serious Common Lisp implementations also allow you to dump a memory image, with all the code already loaded and linked, and such images start quite fast, about 20 ms for a fully loaded image on sbcl, about 35 ms on clisp; and you can portably dump an image using my cl-launch utility by just adding --output /path/to/executable --dump ! to the very same command you'd use to start a script. Thus, at the expense of an extra but trivial build step that takes many seconds once, you can portably transform your slow-starting scripts into a precompiled executable, that will have startup time competitive with other scripting language, and efficiency competitive with other compiled languages.

The problem is that such an image has a significant overhead in terms of space: an empty cl-launch program has an image of size 13MB with CLISP, 28MB on CCL, or 52MB on SBCL (which isn't that bad when you consider this contains the entire compiler and basic libraries — GCC is bigger than that!); an image with all the code I want loaded takes 27MB on CLISP, 50MB on CCL, 82MB on SBCL. A poly-deca-megabyte image file is no big deal. The biggest of these images is 1% of the memory of my laptop. So, by today's standards, it's a small additive overhead. But if you need one image per script, then 80MB of memory to execute a 2KB script is a multiplicative factor 40000 in memory waste — and that is not acceptable if like me you want to replace lots of small shell scripts with Common Lisp code. Compare that to the incremental space expenditure for each additional 1KB of scripting code, which is typically between 1KB and 10KB of additional size for the image, a reasonable factor of 1 to 10. This suggests an obvious solution: to share the image-dumping expenditure between all your CL scripts, so the space overhead is back to a negligible additive overhead and reasonable multiplicative factor, instead of being an outrageous multiplicative factor.

busybox made popular the old concept of a multi-call binary: a same executable binary program that when executed behaves differently based on what name the program was called, such that by using multiple symbolic links (or hardlinks) to the same program, you can replace multiple different binaries with a single one, benefitting from both the sharing effects of dynamic linking and the optimizations of static linking. The same can be done for Common Lisp code. Xach's buildapp already let you do that on SBCL then on CCL using its option --dispatched-entry. I just enriched cl-launch 4.1.2 to support the very same interface on all its 12+ supported implementations (well, the same interface, modulo a different treatment of corner cases). Now, I already share the same executable for 7 personal use scripts, and will only use CL for new scripts while slowly migrating all my old scripts.

The feature was a hundred lines of code total, including comments, documentation and a new cl-launch-dispatch.asd file; the Lisp support for this feature is only loaded on-demand if you use --dispatched-entry, at which point it is marginally free to load a tiny additional ASDF system. I love how Common Lisp lets me implement this feature in such a modular way. Here is the documentation:

  • If option -DE --dispatch-entry is used, then the next argument must follow the format NAME/ENTRY, where NAME is a name that the program may be invoked as (the basename of the uiop:argv0 argument), and ENTRY is a function to be invoked as if by --entry when that is the case. Support for option -DE --dispatch-entry is delegated to a dispatch library, distributed with cl-launch but not part of cl-launch itself, by
    1. registering a dependency on the dispatch library as if --system cl-launch-dispatch had been specified (if not already)
    2. if neither --restart nor --entry was specified yet, registering a default entry function as if by --entry cl-launch-dispatch:dispatch-entry.
    3. registering an init-form that registers the dispatch entry as if (cl-launch-dispatch:register-name/entry "NAME/ENTRY" :PACKAGE) had been specified where PACKAGE is the current package. See the documentation of said library for further details.

    Now, this is a great workaround, but doesn't fully solve the original issue. To completely solve it, an obvious strategy would be for some implementation to radically optimize loading of compiled objects (so called FASL files, for FASt Loading, which some jest should be renamed SLOw Loading), so it becomes actually fast. For instance, the compiler could produce a prelinked object that optimistically assumes it knows the load address, that there will be no conflict in symbol tables, class and method definitions, etc., and at runtime patches only a minimal set of pointers in the usual case. Doing it for 12+ implementations is not doable, but only one suffices, say SBCL or CCL. Alternatively, an "incremental image" feature might do, whereby one could dump all the symbols in some set of packages and not others, with associated functions, classes, etc.; it would require minor change in programmers' habits, though, so is less likely to happen. But any such complete solution will require hacking into the guts of a CL implementation, and that's no small undertaking.

    Assuming we are not going to improve the underlying implementations, a more long-winded "solution" might be to extend the workaround until it becomes a solution: enabling the automatic sharing of executables between all the programs that matter. The old Common-Lisp-Controller from Debian could be resurrected, to create shared images and/or shared executables for software installed by the system's package manager; a similar mechanism could declaratively manage all the programs of a given user (possibly layered on top of the above when available). This might require some tweaks to ASDF so that it doesn't try to build pre-built software from system-managed directories using system-managed implementations, but compiles the usual way when there is a user-specified upgrade, the software wasn't built, or the implementation isn't system-managed. Importantly, there must not be an insecure writeable system-wide FASL cache. (i.e. reverting to per-user cache when any write access is required, or somehow talking to a trusted daemon to compile trusted sources with trusted compilers). This workaround through system management is somewhat ugly, though.

    Note that these issues do not affect Common Lisp developers who run the functionality provided by these scripts from the Common Lisp REPL; they can already do that. It only affect users who run the functionality from these scripts from the shell command line or some other external non-Lisp programs. To a Common Lisp developer who needs such a use case, the solution to these issues is now trivial thanks to this new cl-launch feature. But these issues do make it hard for people to publish scripts that will "just work" for end-users — an end-user being someone who shan't be required to manage an installation or configuration step. These end-users will have to either suffer a multi-second pause at startup, or be burdened with a poly-deca-mega-byte executable for every script or set of related scripts they use. And so, the temporary conclusion is that while Common Lisp is in many ways far ahead of competition with respect to being a low-overhead "scripting language", it does at the moment have an issue putting it at a disadvantage against this competition in one crucial way with respect to deployment to end-users.

    Quicklisp newsApril 2015 Quicklisp dist update now available

    · 12 days ago
    This Quicklisp update is supported by my employer, Clozure Associates. If you need commercial support for Quicklisp, or any other Common Lisp programming needs, it's available via Clozure Associates.

    New projects:
    • birch — A simple Common Lisp IRC client library — MIT
    • bytecurry.mocks — Tools to mock functions for unit tests — MIT
    • carrier — An async HTTP client — MIT
    • cl-cookie — HTTP cookie manager — BSD 2-Clause
    • cl-coveralls — Coverage tracker for Coveralls — BSD 2-Clause
    • cl-groupby — groupby: A higher order function named groupby as known from Scala. — MIT
    • cl-openstack-client — OpenStack client libraries — Apache-2.0
    • cl-poker-eval — 7-card hand poker evaluator — BSD
    • cl-shellwords — Common Lisp port of Ruby's shellwords.rb, for escaping and splitting strings to be passed to a shell. — MIT
    • cl-singleton-mixin — provides singleton-mixin class. — MIT
    • dexador — Yet another HTTP client for Common Lisp — MIT
    • duologue — High-level user interaction library for Common Lisp — MIT
    • dyna — Dyna is an AWS DynamoDB ORM for Common Lisp. — MIT
    • find-port — Find open ports programmatically. — MIT
    • fmt — Extensible format-like facility — MIT
    • folio2 — the folio2 functional-idioms system — Lisp Lesser GNU Public License
    • immutable-struct — Library that encourage the use of functional programming + pattern matching — LLGPL
    • jonathan — JSON encoder and decoder. — MIT
    • json-responses — Canned JSON responses for Hunchentoot — MIT
    • kebab — Common Lisp string,symbol,keyword PascalCase <=> camelCase <=> snake_case <=> kebab-case(lisp-case) converter. — LLGPL
    • lack — A minimal Clack — LLGPL
    • metap — Metap provides metaclass propagation along class inheritance structure. — MIT
    • nsort — Natural or Numeric Sort — BSD Simplified
    • plump-bundle — A binary storage format for Plump documents. — Artistic
    • proc-parse — Procedural vector parser — BSD 2-Clause
    • quadtree — Quadtree data structure in Common Lisp — MIT
    • quasiquote-2.0 — Writing macros that write macros. Effortless. — MIT
    • scriba — A markup format similar to Scribe. — MIT
    • should-test — Minimal yet feature-rich Common Lisp test framework. — MIT
    • string-escape — Emacs and Python style string escapes in #"..." form. — GPLv3
    • thorn — A CommonDoc extension for entering special characters. — MIT
    • trivia — NON-optimized pattern matcher compatible with OPTIMA, with extensible optimizer interface and clean codebase — LLGPL
    • trivia.balland2006 — Optimizer for Trivia based on (Balland 2006) — LLGPL
    • type-i — Type Inference Utility on Fundamentally 1-arg Predicates — LLGPL
    • type-r — Collections of accessor functions and patterns to access the elements in compound type specifier, e.g. `dimensions' in `(array element-type dimensions)' — LLGPL
    • unix-opts — minimalistic parser of command line arguments — MIT
    Updated projects: 3bmd, access, antik, arrow-macros, buffalo, buildapp, chanl, cl-ana, cl-annot, cl-ansi-term, cl-async, cl-charms, cl-dbi, cl-dot, cl-factoring, cl-gobject-introspection, cl-grace, cl-indeterminism, cl-launch, cl-libyaml, cl-mlep, cl-mtgnet, cl-mw, cl-netstring-plus, cl-openid, cl-ply, cl-python, cl-quickcheck, cl-random, cl-readline, cl-reddit, cl-redis, cl-rlimit, cl-sdl2, cl-slug, cl-svg, cl-syntax, cl-tcod, cl-vectors, cl-voxelize, cl-yaml, clack, classimp, clavier, clhs, clim-widgets, clinch, clipper, clos-fixtures, closer-mop, clsql-helper, clx, codata-recommended-values, colleen, com.informatimago, common-doc, common-doc-plump, common-html, commonqt, croatoan, defclass-std, djula, drakma, eazy-project, esrap-liquid, fare-memoization, fast-http, fast-io, femlisp, gendl, graph, gsll, hdf5-cffi, hl7-client, hl7-parser, http-body, hu.dwim.util, hunchentoot, hyperluminal-mem, integral, interface, introspect-environment, js-parser, jsown, jwacs, lass, let-over-lambda, lfarm, linedit, lisp-interface-library, lisp-invocation, lisp-namespace, local-time, lucerne, magicffi, mcclim, media-types, mgl-pax, mk-string-metrics, nibbles, ningle, nst, plump, protobuf, qtools, quri, quux-time, racer, rutils, scalpl, scriptl, sdl2kit, serapeum, shellpool, simple-rgb, skippy, slime, st-json, staple, stumpwm, symbol-munger, trivial-backtrace, trivial-benchmark, trivial-debug-console, trivial-download, trivial-update, umlisp, verbose, vertex, vgplot, weblocks-stores, weft, workout-timer, xmls, zaws, zcdb, zpb-exif, zpng.

    Removed projects: autoproject, brlapi, cambl, cl-couch, cl-ledger, hctsmsl, nekthuth, red-black.

    To get these updates, use (ql:update-dist "quicklisp").


    Quicklisp newsMarch 2015 download stats

    · 14 days ago
    Here are the top 100 download for last month:

     5853   alexandria
    4149 cl-ppcre
    3465 closer-mop
    3382 trivial-features
    3296 babel
    3086 named-readtables
    2977 cffi
    2814 flexi-streams
    2795 bordeaux-threads
    2785 trivial-gray-streams
    2784 cl+ssl
    2722 cl-fad
    2641 trivial-garbage
    2315 nibbles
    2313 usocket
    2277 chunga
    2251 anaphora
    2235 cl-base64
    2218 optima
    2142 split-sequence
    1942 ironclad
    1839 puri
    1803 fiveam
    1768 iterate
    1753 drakma
    1729 chipz
    1641 cl-colors
    1629 trivial-backtrace
    1586 local-time
    1559 md5
    1493 slime
    1486 let-plus
    1401 fare-utils
    1392 fare-quasiquote
    1340 cl-ansi-text
    1190 prove
    1180 hunchentoot
    1098 cl-unicode
    1072 trivial-types
    1053 rfc2388
    1021 metabang-bind
    1010 cl-utilities
    986 cl-interpol
    961 cl-syntax
    950 trivial-utf-8
    889 introspect-environment
    846 quicklisp-slime-helper
    827 cl-annot
    802 parse-number
    757 st-json
    716 quri
    710 osicat
    709 postmodern
    686 cl-marshal
    658 trivial-mimes
    654 xsubseq
    651 lparallel
    648 plump
    645 jsown
    641 asdf-system-connections
    614 ieee-floats
    613 trivial-indent
    605 metatilities-base
    604 uuid
    603 array-utils
    601 cl-containers
    596 cl-json
    590 lquery
    584 fast-http
    572 cl-sqlite
    567 salza2
    556 clss
    538 clack
    500 static-vectors
    495 clx
    490 command-line-arguments
    464 cl-markdown
    463 py-configparser
    462 dynamic-classes
    455 circular-streams
    446 asdf-finalizers
    446 zpb-ttf
    446 cl-log
    445 fast-io
    443 cl-abnf
    442 garbage-pools
    440 buildapp
    435 cl-mssql
    425 cl-who
    399 zpng
    397 esrap
    395 http-body
    394 vecto
    391 cl-csv
    389 cl-vectors
    388 iolib
    358 closure-common
    353 lisp-namespace
    351 cl-opengl
    351 cl-dbi

    Zach BeaneGo-to libraries

    · 14 days ago

    I got a lot of interesting responses last week to my request forlibraries. Many people sent their CL library stack to me, with commentary. I don’t want to list every single library; there were a few libraries that stood out with multiple mentions from different people. Here they are.

    cl-store - I reach for it when a problem is in the gap between simple serializing with s-expressions and complex serialization with a custom scheme.

    cl-smtp - for sending mail via SMTP. cl-pop and smtp4cl are also used by multiple people.

    plexippus-xpath and xuriella - for XPath and XSLT. DJ wrote: “I am writing a CL library system of sorts that grabs data from many online services (Library of Congress and many others). These services mostly supply XML, so getting at the content I want requires use of xslt and xpath. Sometimes json is available, but since I am fairly good at xslt/xpath from work a decade ago, why bother?”

    clsql - for database access

    serapeum - for utilities

    uiop - for filesystem access; cl-fad was also plugged a few times

    html-template, cl-who, and parenscript - for client-side HTML and JavaScript generation

    closure-html - for parsing HTML

    usocket - for portable networking

    log5 and cl-log - for logging

    lparallel - for managing parallel tasks via threads

    split-sequence - string splitting

    ironclad - for cryptographic operations

    local-time - for working with dates and times

    Multiple people plugged Quicklisp as the way to get their favorite libraries, which always makes me happy. 

    There were a few test libraries mentioned, but not as many as I expected. If you have a favorite way to test your code, and you think everyone should know about it, let me know.

    LispjobsClojure/Clojurescript Web Developer, Kira Systems, Toronto or Remote

    · 22 days ago

    We're looking for a developer to work on our Clojure/ClojureScript/Om web stack. Our team is small, pragmatic, and inquisitive; we love learning new technologies and balance adoption with good analysis.  We prefer to hire near us, but also welcome remote work in a time zone within North America.

    Web technology can be built better. If single-page web design driven by a reactive data model sounds interesting to you, get in touch!

    Technologies we use:

    • HTML, CSS, SASS,
    • Clojure, ClojureScript,
    • SQL, PostgreSQL, Java,
    • and experience with web app security.

    You should have knowledge of some of these. Most of all we look for those interested in learning.

    This position starts immediately.

    Application link: Clojure/Clojurescript Web Developer

    Zach BeaneYour go-to libraries

    · 24 days ago

    Here are some of the libraries I reach for when I want to do stuff:

    • alexandria for general utilities
    • chirp for twitter
    • yason for processing/generating json
    • cl-ppcre for regular expressions
    • cxml for processing/generating XML
    • Postmodern for database work
    • Hunchentoot for web work
    • drakma as a HTTP client
    • cl-pdf and Vecto for making PDFs and PNGs
    • function-cache for memoization and caching

    What are some of the libraries you use for day-to-day programming tasks? Email me and I'll summarize next week.

    Patrick SteinTrying Clojure again?

    · 25 days ago

    EDIT: Indeed, as people on Reddit pointed out, installing Lein is simply downloading a script and running it. Installing CIDER from MELPA was also easy. The two, however, aren’t completely compatible at the moment because CIDER from MELPA wants nREPL 0.2.7 at least and Lein only pulls in 0.2.6 (even though, I believe the current is 0.2.10).

    It has been five years since I last tried Clojure. I feel like I should try it again.

    I don’t want to beat my head against Leiningen for even ten minutes this time. Is there some way to reasonably use Emacs + Clojure without have to install and configure CLASSPATHS and Mavens and Ants and JDKs?

    It seems SWANK-CLOJURE has been deprecated in favor of CIDER. The CIDER doc says how to configure Leiningen or Boot for use with CIDER. Is there some way that I can avoid Leingingen and Boot? Or some way that I can click one ‘Install’ button and have Leiningen and Boot work?

    Christophe Rhodesels2015 is nearly here

    · 31 days ago

    This year, I have had the dubious pleasure of being the Local Organizer for the European Lisp Symposium 2015, which is now exactly one month away; in 31 days, hordes of people will be descending on South East London New Cross Gate to listen to presentations, give lightning talks and engage in general discussions about all things Lisp - the programme isn't quite finalized, but expect Racket, Clojure, elisp and Common Lisp to be represented, as well as more... minority interests, such as C++.

    Registration is open! In fact, for the next nine days (until 29th March) the registration fee is set at the absurdly low price of €120 (€60 for students) for two days of talks, tutorials, demos, coffee, pastries, biscuits, convivial discussion and a conference dinner. I look forward to welcoming old and new friends alike to Goldsmiths. newsGitLab migration and Go-Live

    · 32 days ago

    Progress of the GitLab installation and migration scripts has been very good. With some last tests to go, we’re confident we can complete installation and migration on Friday March 20th, 2015. The window 08:00h - 12:00h UTC has been designated to perform installation and migration. For more details continue reading below the fold.

    During that window existing git repositories with public visibility (i.e. http or gitweb access – git:// access not counted) will be migrated into GitLab 1. There’s no impact on Subversion, CVS, mercurial, darcs or bazaar repositories. Users with git repositories without http or gitweb access, who want to use GitLab for their project are kindly requested to contact the site admins.

    After the migration, migrated repositories will be removed from their current physical path locations. Repositories will only be accessible through GitLab and stored in a location managed by GitLab. Users who want to make backups should do so by keeping a local clone of their git repository(-ies).

    As part of the migration, GitLab accounts will be created for all users of the system. Each user with a .forward file in their home directory on the system will receive an account confirmation e-mail. This confirmation request is valid for 48 hours. All accounts must be confirmed before use - the system blocks accounts until confirmed. Your account can be used immediately after confirmation, even during the migration window. As part of the migration, SSH keys found in the user’s home directory will be imported into the user’s GitLab account. You will receive an e-mail to confirm this happened.

    As part of the migration, Gitlab groups will be created, mirroring the “project” concept. Users currently part of a project by virtue of being member of a unix group on will be assigned GitLab group membership for the mirror group in the role of Owner. Notification mails are sent out due to the migration process. Projects that wish to use GitLab’s more fine-grained permisssions2 can do so after migration completes.

    As part of the migration, existing git repositories will be imported into GitLab under the group or account which mirrors the project or account. All repositories will have a public visibility. Each repository on becomes a project in GitLab. This means each repository gets an issue tracker and wiki set up. Any project that wishes not to use those can turn those off in the Settings page for the GitLab project after the migration. Due to the nature of the migration process, the Administrator account will be a member of all GitLab projects and groups. This can be corrected after the migration.

    After the migration, gitweb access won’t be available anymore. It will be replaced by URL redirection to GitLab. git:// protocol support won’t be available anymore either.

    While the migration is in progress, SSH access to the system will be blocked to prevent repositories being updated while migrated.

    Should you want to start a new project in GitLab, please ask the site admins to create a group for it.

    Please note that this is just one of the steps in the restructuring plan for Further steps as indicated in 3 will be executed later and will affect repositories for other version control systems as well as other services.

    In case of questions please follow up to clo-devel at the announcements mailing list is closed for posting.

    LispjobsSoftware Developer for Quantum Processor Development group, D-Wave Systems, Vancouver, British Columbia

    · 35 days ago

    D-Wave is seeking an experienced Software Developer to join the Processor Development group. The successful candidate will work closely with physicists to develop and optimize measurement routines used to calibrate D-Wave’s quantum processor.
    You will be self-driven, but comfortable working closely with others. You will share responsibility for designing, implementing, testing and maintaining the suite of software necessary to support the testing and operation of D-Wave's quantum computing hardware.The software is implemented in Common Lisp (SBCL) and is an integral part of the quantum computing system. It is used for a variety of purposes including calibration, operation, testing and benchmarking.

    See the full announcement:

    Christophe Rhodestmus research programmer position

    · 35 days ago

    The AHRC-funded research project that I am a part of, Transforming Musicology, is recruiting a developer for a short-term contract, primarily to work with me on database systems for multimedia (primarily audio) content. The goal for that primary part of the contract is to take some existing work on audio feature extraction and probabilistic nearest-neighbour search indexing, and to develop a means for specialist users (e.g. musicologists, librarians, archivists, musicians) to access the functionality without needing to be experts in the database domain. This of course will involve thinking about user interfaces, but also about distributed computation, separation of data and query location, and so on.

    The funding is for six months of programmer time. I would have no objection to someone working for six months in a concentrated block of time; I would also have no objection to stretching the funding out over a longer period of calendar time: it might well provide more time for reflection and a better outcome in the end. I would expect the development activities to be exploratory as well as derived from a specification; to span between the systems and the interface layer; to be somewhat polyglot (we have a C++ library, bindings in Python, Common Lisp and Haskell, and prototype Javascript and Emacs front-ends - no applicant is required to be fluent in all of these!)

    There are some potentially fun opportunities during the course of the contract, not least working with the rest of the Transforming Musicology team. The post is based at Goldsmiths, and locally we have some people working on Systems for Early Music, on Musicology and Social Networking, and on Musical Memory; the Goldsmiths contribution is part of a wider effort, with partners based at Oxford working on Wagnerian Leitmotif and on a Semantic Infrastructure, at Queen Mary working on mid-level representations of music, and in Lancaster coordinating multiple smaller projects. As well as these opportunities for collaboration, there are a number of events coming up: firstly, the team would hope to have a significant presence at the conference of the International Society for Music Information Retrieval, which will be held in Málaga in October. We don't yet know what we will be submitting there (let alone what will be accepted!) but there should be an opportunity to travel there, all being well. In July we'll be participating in the Digital Humanities at Oxford Summer School, leading a week-long programme of workshops and lectures on digital methods for musicology. Also, in November of 2014, we also participated in the AHRC's "Being Human" festival, with a crazy effort to monitor participants' physiological responses to Wagner opera; there's every possibility that we will be invited to contribute to a similar event this year. And there are other, similar projects in London with whom we have friendly relations, not least the Digital Music Lab project at City University and the EU-funded PRAISE project at Goldsmiths.

    Sound interesting? Want to apply? There's a more formal job advert on the project site, while the "person specification" and other application-related materials is with Goldsmiths HR. The closing date for applications is the 27th March; we'd hope to interview shortly after that, and to have the developer working with us from some time in May or June. Please apply!


    · 43 days ago
    Domain going free to a good home, needs renewing in May. Get in touch if you're interested.

    ECL NewsECL 15.3.7 released

    · 44 days ago

    My deep apologies to all Windows users for misfortunate unicode
    character at top screen, which caused an exception at the very start
    of ECL startup. Version 15.2.21 was released little
    prematurely. Proper fix is released a week after problem was noticed,
    because we did want to test it first, and to fix a few regressions
    between 13.5.1 and 15.2.21.

    This release is at least as good as 15.2.21. Enchantments include:

    • ECL now builds easily with Visual Studio 2012, including builds with
      custom codepages,
    • Autoconf scripts are upgraded to version 2.69,
    • Fixed stack direction, so builds against upcoming gcc 5.0 should
    • Broken --with-sse=yes configure flag works once again,
    • Fixed stable-sort bug (corner case on sorting strings),
    • Lasers.

    Big thanks to everyone, who helped with testing and development :-)

    Regarding other news, we're still on a move. We barely settled on
    gitorious and now it's aquired by gitlab, so we're moving forward, to
    gitlab. But not everything at once. Full migration will be performed
    at 14th march, but repositories are already synced, and wiki is moved
    as well (some links are broken, but it's a matter of a few
    edits). Anyone interested on participating, is invited to join a team
    at .

    Zach BeaneUsing paredit within screen

    · 44 days ago

    I often persist Common Lisp services via screen. This works pretty well. One downside is the handling of paredit keys through an ssh+screen pipeline: by default, a key like C-right produces the text 5C in my buffer.

    To fix, I’ve been copying these lines around to my .emacses:

    (define-key input-decode-map "\M-[1;5A" [C-up])
    (define-key input-decode-map "\M-[1;5B" [C-down])
    (define-key input-decode-map "\M-[1;5C" [C-right])
    (define-key input-decode-map "\M-[1;5D" [C-left])
    (define-key input-decode-map "\M-[1;3A" [M-up])
    (define-key input-decode-map "\M-[1;3B" [M-down])
    (define-key input-decode-map "\M-[1;3C" [M-right])
    (define-key input-decode-map "\M-[1;3D" [M-left])
    (define-key input-decode-map "\M-[1;9A" [M-up])
    (define-key input-decode-map "\M-[1;9B" [M-down])
    (define-key input-decode-map "\M-[1;9C" [M-right])
    (define-key input-decode-map "\M-[1;9D" [M-left])

    With those keys configured, my most-used paredit commands work as expected.

    This might not be the best fix, but I couldn’t find anything better via search. If you know better, tell me.

    Quicklisp newsMarch 2015 Quicklisp dist update now available

    · 48 days ago
    New projects:
    • arrow-macros — arrow-macros provides clojure-like arrow macros and diamond wands. — MIT
    • buffalo — A LALR(1) parser generator for Common Lisp — MIT/X11
    • burgled-batteries — Lisp-Python interface — MIT
    • burgled-batteries.syntax — Embedded Python syntax for burgled-batteries — MIT
    • cl-libyaml — A binding to the libyaml library. — MIT
    • cl-mlep — cl-mlep is a Common Lisp Machine Learning library for Educational Purposes. — MIT
    • cl-mtgnet
    • cl-netstring-plus — A simple library for sending and receiving messages with a netstring-like encoding
    • cl-reddit — Reddit client api library — BSD
    • cl-yaml — A YAML parser and emitter. — MIT
    • cl4store — 4store — BSD
    • clavier — Clavier: A Common Lisp validation library — MIT
    • clipper — File attachment library. — MIT
    • clods-export — Common Lisp OpenDocument spreadsheet export library — MIT
    • common-doc-plump — Translate a Plump DOM into a CommonDoc document and back. — MIT
    • descriptions — A domain model meta level description library — MIT
    • eazy-process — Yet Another Portable Library for Process Handling / Subshell Invokation — MIT
    • hl7-client — hl7-client - send HL7-Messages over TCP/IP with MLLP — BSD
    • hl7-parser — Decoder and Encoder for ER7 formatted HL7-Messages — BSD
    • hyperluminal-mem — High-performance serialization library, designed for untrusted data — LLGPL
    • linewise-template — Linewise file/stream processor for code generation etc. — BSD-3-Clause
    • lisp-namespace — Provides LISP-N --- extensible namespaces in Common Lisp. — LLGPL
    • media-types — Query and compare media types. — MIT
    • ryeboy — Riemann client — BSD
    • shellpool — A library for running external programs from Common Lisp — MIT/X11-style
    • transparent-wrap — A signature-preserving wrapper generator for functions and macros. — LLGPL
    • trivial-debug-console — A library for a well-behaved debug console
    • vertex — A markup language with TeX syntax. — MIT
    • weft
    • workout-timer — Workout timer — MIT
    Updated projects: architecture.service-provider, asdf-linguist, avatar-api, basic-binary-ipc, binge, blackbird, caveman, chanl, chillax, chrome-native-messaging, cl+ssl, cl-acronyms, cl-ana, cl-ansi-term, cl-async, cl-autowrap, cl-charms, cl-cli, cl-colors, cl-conspack, cl-csv, cl-custom-hash-table, cl-db3, cl-dbi, cl-devil, cl-fsnotify, cl-gobject-introspection, cl-gss, cl-i18n, cl-l10n, cl-libuv, cl-marshal, cl-messagepack, cl-mock, cl-murmurhash, cl-mysql, cl-openal, cl-opengl, cl-prime-maker, cl-python, cl-rabbit, cl-read-macro-tokens, cl-readline, cl-redis, cl-rethinkdb, cl-rlimit, cl-sdl2, cl-slug, cl-speedy-queue, cl-twitter, cl-webkit, cl-xul, cl-yaclyaml, clack, clack-errors, clfswm, clim-widgets, clip, clos-fixtures, closer-mop, clot, clpmr, clsql, clss, clx, cobstor, colleen, com.informatimago, common-doc, common-html, commonqt, corona, crane, defclass-std, defenum, dissect, djula, drakma-async, eazy-gnuplot, eazy-project, eco, esrap, esrap-liquid, external-program, fast-http, form-fiddle, gbbopen, gendl, http-body, hunchensocket, integral, iolib, lisp-executable, lparallel, lquery, lucerne, mgl-pax, micmac, mime4cl, mk-string-metrics, modularize-interfaces, myway, named-readtables, net4cl, nibbles, optima, osicat, packet, pgloader, piping, plump, pooler, qlot, qmynd, qtools, quri, racer, rcl, rock, scalpl, sclf, sdl2kit, serapeum, sheeple, simple-currency, skippy, smtp4cl, south, spinneret, squirl, st-json, staple, stmx, stumpwm, sxql, talcl, trivial-arguments, trivial-benchmark, trivial-download, trivial-extract, trivial-mimes, trivial-update, unix-options, until-it-dies, utils-kt, utm, verbose, weblocks, weblocks-utils, woo, wookie.

    Removed projects: 3bil, cl-binaural, cl-openstack, cluck, lisphys, oct.

    I removed 3bil because it is effectively unmaintained and apparently unused. cl-openstack is no longer maintained; a replacement library will soon be available. I can't build cl-binaural, cluck, lisphys, or oct on SBCL any more.

    Sorry to skip a release in February. A holiday and a number of library problems conspired to hold off the release. As a result there are a larger number of updates this month than usual. If you have any problems, please don't hesitate to discuss them on the mailing list or email me directly.

    To get this update, use (ql:update-dist "quicklisp").


    Quicklisp newsFebruary 2015 download stats

    · 49 days ago
    Here are the top 100 download for last month:

     4270   alexandria
     2825   trivial-features
    2753 cl-ppcre
    2740 babel
    2464 closer-mop
    2316 cl-fad
    2309 bordeaux-threads
    2211 cffi
    2126 iterate
    2103 trivial-garbage
    2063 slime
    2042 flexi-streams
    1944 trivial-gray-streams
    1867 split-sequence
    1771 anaphora
    1744 chunga
    1651 cl+ssl
    1646 usocket
    1601 local-time
    1558 cl-base64
    1441 metabang-bind
    1327 trivial-backtrace
    1304 named-readtables
    1292 drakma
    1277 nibbles
    1249 puri
    1234 ironclad
    1230 md5
    1206 optima
    1152 chipz
    988 trivial-types
    948 hunchentoot
    893 cl-utilities
    885 cl-unicode
    813 rfc2388
    784 let-plus
    777 quicklisp-slime-helper
    777 stefil
    753 cl-interpol
    745 trivial-utf-8
    729 cl-syntax
    724 cl-annot
    714 quri
    706 postmodern
    658 parse-number
    630 fiveam
    611 cl-colors
    591 salza2
    561 cl-json
    542 log4cl
    514 cl-ansi-text
    511 lparallel
    500 cl-who
    482 prove
    482 ieee-floats
    481 zpb-ttf
    473 zpng
    461 vecto
    453 cl-sqlite
    437 uuid
    433 cl-vectors
    425 cl-yacc
    423 st-json
    417 asdf-system-connections
    403 osicat
    394 parenscript
    385 metatilities-base
    383 cl-containers
    374 clx
    368 buildapp
    367 closure-common
    364 clack
    355 yason
    346 command-line-arguments
    345 fare-utils
    341 iolib
    335 cxml
    335 cl-marshal
    324 static-vectors
    312 fare-quasiquote
    309 xsubseq
    308 dynamic-classes
    304 py-configparser
    301 cl-markdown
    299 fast-http
    297 asdf-finalizers
    293 cl-log
    288 external-program
    286 trivial-indent
    286 cl-abnf
    282 garbage-pools
    279 plump
    279 cl-mssql
    274 contextl
    271 cl-opengl
    268 trivial-mimes
    264 html-template
    262 fast-io
    251 array-utils
    249 zs3

    Gábor MelisOn the Design of Matrix Libraries

    · 54 days ago

    I believe there is one design decision in MGL-MAT that has far reaching consequences: to make a single matrix object capable of storing multiple representations of the same data and let operations decide which representation to use based on what's the most convenient or efficient, without having to even know about all the possible representations.

    This allows existing code to keep functioning if support for diagonal matrices (represented as a 1d array) lands and one can pick and choose the operations performance critical enough to implement with diagonals.

    Adding support for matrices that, for instance, live on a remote machine is thus possible with a new facet type (MAT lingo for representation) and existing code would continue to work (albeit possibly slowly). Then one could optimize the bottleneck operations by sending commands over the network instead of copying data.

    Contrast this with what I understand to be the status quo over on the Python side. The specialized Python array libs (cudamat, gpuarray, cudandarray) try to be drop-in replacements for - or at least similar to - numpy.ndarray with various degrees of success. There is lots of explicit conversion going on between ndarray and these CUDA blobs and adding new representations would make this exponentionally worse.

    Torch (Lua) also has CUDA and non-CUDA tensors are separate types, and copying between main and GPU memory is explicit which leads to pretty much the same problems.

    All of this is kind of understandable. When one thinks in terms of single-dispatch (i.e. object.method()), this kind of design will often emerge. With muliple-dispatch, data representation and operations are more loosely coupled. The facet/operation duality of MGL-MAT is reminiscent of how CLOS classes and generic functions relate to each other. The anology is best if objects are allowed to shapeshift to fit the method signatures.

    Speaking of multiple-dispatch, by making the operations generic functions following some kind of protocol to decide which facets and implementation to use would decouple facets further. Ultimately, this could make the entire CUDA related part of MGL-MAT an add-on.

    Zach BeaneLogical pathnames and eager parsing

    · 54 days ago

    Here’s something that cost me some time debugging today:

      (setf (logical-pathname-translations "bug")
            (list (list "bug.lisp.*" "/tmp/bug.lisp")))
      (print (list :bug (probe-file #p"bug:bug.lisp")))

    The above form will print (:BUG NIL) in SBCL, even if /tmp/bug.lisp exists. That’s because #p"bug:bug.lisp" is approximately equivalent to #.(parse-namestring "bug:bug.lisp"), which happens at read time. Since the BUG logical host isn’t defined by then, SBCL parses the string as a pathname with a name of “bug:bug” and a type of “lisp”.

    Using the string "bug:bug.lisp" instead of the form #p"bug:bug.lisp" defers namestring parsing until runtime. By then, the logical host is defined and the translation kicks in, and the probe-file returns #p"/tmp/bug.lisp" as expected.

    (Namestring syntax and parsing is, of course, implementation-dependent. In Clozure CL, a colon is always interpreted as a logical host delimiter, and the progn form above signals an error. To use a colon in a “normal” pathname, it must be prefixed with a backslash in its namestring.)

    LispjobsClojure SDE,, Seattle Washington (repost, with new contact info)

    · 56 days ago is the leading online retailer in the United States with over $75 billion in global revenue. At Amazon, we are passionate about using technology to solve business problems that have big customer impact.  CORTEX is our next generation platform which handles real-time financial data flows and notifications. Our stateless event-driven compute engine for dynamic data transforms is built entirely in Clojure and is crucial to our ability to provide a highly agile response to financial events within the organization. We leverage AWS to operate on a massive scale and meet high-availability, low-latency SLAs.  If you have over 7 years of experience as a hands-on software developer, have worked with distributed systems, and have experience in start-ups or possess a "start-up mentality", keep reading.

    Do you:

    • Obsess over software performance and challenge yourself and others to deliver highly scalable, low latency, reliable and fast computation platforms?
    • Possess great ideas and know how to solve problems, but also follow through with a clean and maintainable implementation?
    • Have a high bar for coding excellence and a passion for design and architecture?
    • Want to work with really cool technology such as Clojure, JVM, and AWS tools?
    • Either live in or desire to live in the greater Seattle area and want to work somewhere that you can have a large scale impact but still work on a small team?

    If your answers are yes, this may be the role for you!  Combining a startup atmosphere with the ambition to build and utilize cutting-edge reactive technology, the Cortex team at Amazon is looking for a passionate, results-oriented, and innovative Sr. Software Engineer who wants to move fast and have fun, while being deeply involved in solving business integration problems across various organizations within Amazon.

    Basic Qualifications

    • 3+ years of experience designing, building, deploying, operating, scaling, and evolving distributed systems and high-volume transaction application in a 24/7 environment
    • 7+ years of industry experience in software development in Java or C++
    • Exceptional customer relationship skills including the ability to discover the true requirements underlying feature requests, recommend alternative technical and business approaches, and lead engineering efforts to meet aggressive timelines with optimal solutions
    • Bachelor’s Degree in Computer Science or related field or equivalent work experience

    Preferred Qualifications

    • Background or strong interest in Clojure
    • Experience with cloud technologies from AWS
    • Proficiency in a Unix/Linux environment
    • Graduate degree (MS/PhD) a plus
    • Experience mentoring and developing junior SDEs

    If interested, please send your resume to

    ECL NewsECL 15.2.21 released, new maintainer found

    · 58 days ago

    New release, which is mainly current state of git HEAD (plus a few fixes). Contains numerous bug-fixes in comparison to 13.5.1 and is last, which follows date-based version convention. It's time to finally release ECL 1.0 ;-).

    Development moves to gitorious (, same as wiki (previous content is inaccessible now, but once subscription is renewed, I'll start to migrate content from there). In GIT topic - current permissions will be preserved. Just drop me a line with gitorious login, and I'll add person on corresponding permission level to project.

    Mailing list and website are staying at SF for now, but I'd really like to switch the latter to something more manageable. Also, SF have lately problems with stability, what is quite annoying.

    More on maintainer topic:
    My name is Daniel Kochmański (you may meet me on IRC and over internet under the nick "jackdaniel") and I'm willing to spare at least a few hours a week for this amazing project to keep it alive. More on progress ideas and myself might be found on mailing list archive - I ask for comments, suggestions and discussion (and forgiveness for some potential dumb ideas I might propose), to develop them better. Also, I do ask for help.

    While I will try to set up Linux/Unix environment to check builds and try to fix problems on various operating systems (I'm thinking about putting vagrant in use), I have no access to neither Windows or OSX environments, so I will have no clue, if any commit will break builds on these. Testers for these platforms are crucial imo.

    Best regards,

    Gábor MelisBigger and Badder PAX World

    · 60 days ago

    Bigger because documentation for named-readtables and micmac has been added.

    Badder because clicking on a name will produce a permalink such as this: *DOCUMENT-MARK-UP-SIGNATURES*. Clicking on locative types such as [variable] on the page that has just been linked to will take you to the file and line on github where *DOCUMENT-MARK-UP-SIGNATURES* is defined.

    LispjobsLisp Hacker with interest in Machine Intelligence

    · 66 days ago

    I’m hiring a hacker or two for a startup.
    Please send CV, portfolio & phone number.

    Devon Sean McCullough

    (Write him for location, description, etc)

    Nicolas HafnerUsing CL+Qt - Confession 49

    · 67 days ago

    header Some deem it unfortunate, others are not bothered by it at all, but the fact remains that Common Lisp does not have a standard GUI toolkit. It does have a native toolkit called McCLIM, but due to general outdated-ness it is not a very attractive choice. Generally I'm not one to linger long on decisions when it comes to learning something, so after quickly evaluating the options I chose to try CommonQt, a library to allow using the Qt framework with CL.

    The first thing I wrote with it was a primitive GUI for a chat client, but while I did finish it, I never went far with it. That is, until Parasol came along. Parasol makes heavy use of Qt, and unfortunately working with CommonQt forces you to write in a rather un-lispy style. This isn't surprising, since Qt itself is a C++ framework and thus matching idioms probably isn't as easy.

    Fortunately for us, CommonQt already goes a long way of bridging the gap, but not quite far enough. In an effort to bring GUI writing with Qt closer to home, I created Qtools. In this entry we're going to make use of CommonQt and Qtools to show off what writing a basic GUI in CL can look like.

    What we're going to do for this mini project here is write a primitive Twitter client. It'll have a dialog to let users log in via twitter and a main window to display new statuses, as well as let you post some. To make this all possible we'll make use of Chirp and the aforementioned Qtools. In order to understand this tutorial you'll need a moderate understanding of Common Lisp, some prior knowledge of UI programming, and a lack of fear to look things up in the hyperspec, Qt docs, and other documentation. Let's get to it.

    (ql:quickload '(:chirp :qtools))

    This month (February 2015), you'll want to get Qtools from git (version 0.4.2+) as the Quicklisp version is too outdated. In case the CommonQt loading fails, refer to the CommonQt homepage.

    Now, as usual we'll create a new package for ourselves to live in.

    (defpackage #:titter
      (:use #:cl+qt)
      (:export #:main))
    (in-package #:titter)
    (named-readtables:in-readtable :qtools)

    Here you'll notice two deviations from the norm. First, we're not :use-ing the standard CL package, but rather CL+QT, which is a package from Qtools that provides convenient access to CL as well as Qt functionality. Second, we need the in-readtable statement to make use of CommonQt's reader extension for Qt methods.

    Now we'll finally start with writing our own UI. Defining top-level widgets happens with define-widget, which exactly mirrors defclass, with the exception of some extensions that are irrelevant for this tutorial.

    (define-widget login (QDialog)

    This will be our dialog to log in with. You can already test it now, but you won't get much beyond a blank window.

    (with-main-window (w (make-instance 'login)))

    Time to get on to the meat of a widget, its contents. Logging in to twitter can't happen via password anymore unless you get special permission from twitter to do so. We'll instead use twitter's oAuth PIN method. To give that to the user, we'll need to show them a link, let them type in a PIN and have a button to confirm or something.

    (define-subwidget (login url) (#_new QLabel login)
      (#_setTextFormat url (#_Qt::RichText))
      (#_setTextInteractionFlags url (#_Qt::TextBrowserInteraction))
      (#_setOpenExternalLinks url T))

    That's quite a few new things here so let's go through them. define-subwidget as you probably expect defines a widget on our login widget, called url. This initializes to a QLabel instance with our main widget set as parent. #_new is the CommonQt equivalent to the new operator in C++. While widgets defined on the CL side need to be initialised as usual using make-instance, Qt-native classes need to be instantiated using #_new. Next in the body we set a couple of properties of our label using C++ methods with the #_ reader macro. Make sure to type the method names in their exact case or CommonQt won't be able to find them. These property changes are necessary to allow clickable URLs.

    Don't launch your widget quite yet or you'll be disappointed to find it as bleak and empty as before. We'll get to that in a minute, but first let's define the rest of our components real quick.

    (define-subwidget (login pin) (#_new QLineEdit login)
      (#_setPlaceholderText pin "PIN"))
    (define-subwidget (login go) (#_new QPushButton "Login" login))

    Alright, that was easy. Now, the subwidgets won't appear on your main widget magically as the system could not have any idea how you want them to be placed. For this we need layouts.

    (define-subwidget (login layout) (#_new QVBoxLayout login)
      (#_setWindowTitle login "Login to Twitter")
      (#_addWidget layout url)
      (let ((inner (#_new QHBoxLayout)))
        (#_addWidget inner pin)
        (#_addWidget inner go)
        (#_addLayout layout inner)))

    Rather simple layout stuff by GUI standards. A vertically oriented layout to hold our label and a horizontal layout that holds the PIN text field and button. Now you may launch your widget again and marvel at the impressively unexciting UI.

    In order to make things react in Qt you need to employ their system of slots and signals. Slots are signal receptors and signals are identifiers as well as data-carriers for events. So, when a button gets clicked a signal is fired. Whatever slot is connected to the button on that signal then gets called with the signal properties for arguments. Since we have a button in our form, let's make a slot for it.

    (define-slot (login done) ()
      (declare (connected go (released)))
      (#_QMessageBox::information login "OOoOo" \(°_o)/¯"))

    What we've done here is defined a slot on our widget called done, which takes no arguments and is connected to the go button's released signal (which provides no properties). You'll notice here that Qtools uses declarations like a sly fox in order to make things a bit easier and lispier. Firing up the widget now will already give you the expected effect.

    This is all good and well, but it has rather little to do with Twitter, so we'll change that. First, we need to fetch the URL to have the user authenticate with and display it on the label.

    (defun set-url (widget)
      (let ((url (chirp:initiate-authentication
                  :api-key "D1pMCK17gI10bQ6orBPS0w"
                  :api-secret "BfkvKNRRMoBPkEtDYAAOPW4s2G9U8Z7u3KAf0dBUA")))
        (#_setText widget (format NIL "Please enter the pin from <a href=\"~a\">twitter</a>." url))))

    Then we need to change our login slot definition to actually make use of this function.

    (define-subwidget (login url) (#_new QLabel login)
      (#_setTextFormat url (#_Qt::RichText))
      (#_setTextInteractionFlags url (#_Qt::TextBrowserInteraction))
      (#_setOpenExternalLinks url T)
      (set-url url))

    But, we're only half-way there. We still need to actually evaluate the PIN that the user passes back to get the proper authentication credentials. We'll do that in our done slot.

    (defvar *logged-in* NIL)
    (define-slot (login done) ()
      (declare (connected go (released)))
      (setf *logged-in* NIL)
      (#_setCursor login (#_new QCursor (#_Qt::WaitCursor)))
          (chirp:complete-authentication (#_text pin))
        (error (err)
          (#_QMessageBox::critical login "Error!" "Failed to login.")
          (#_setText pin "")
          (set-url url)
          (#_setCursor login (#_new QCursor (#_Qt::ArrowCursor))))
        (:no-error (&rest args)
          (declare (ignore args))
          (setf *logged-in* T)
          (#_close login))))

    So, what happens here? First we have a variable to keep track of the login status and then we do some cursor displaying to let the user know that stuff is happening the back. Next we have error handling in case our authentication fails for some reason, which just resets things to let the user try again. However, if we succeed the widget closes itself and thus returns. To verify that everything logged in smoothly after you've tried it, you can use


    So in, little under 50 lines we wrote a complete login dialog for our application. While we're fired up like that, let's move on to writing the actual client. We'll want a field to type new status updates into, a button to submit the tweet, and a list to hold new tweets from our home timeline.

    (define-widget client (QWidget)
    (define-subwidget (client status) (#_new QLineEdit client)
      (#_setPlaceholderText status "What's old?.."))
    (define-subwidget (client tweet) (#_new QPushButton "Tweet!" client))
    (define-subwidget (client timeline) (#_new QListWidget client)
      (#_setWordWrap timeline T)
      (#_setTextElideMode timeline (#_Qt::ElideNone)))
    (define-subwidget (client layout) (#_new QVBoxLayout client)
      (#_setWindowTitle client "Titter")
      (let ((inner (#_new QHBoxLayout)))
        (#_addWidget inner status)
        (#_addWidget inner tweet)
        (#_addLayout layout inner))
      (#_addWidget layout timeline))

    Mostly similar to what we had before, modulo widgets and properties. Now we need another big function to take care of submitting a tweet. This happens as before in a slot since we need to handle a button press.

    (define-slot (client tweet) ()
      (declare (connected tweet (released)))
      (cond ((<= 1 (chirp:compute-status-length (#_text status)) 140)
             (#_setCursor client (#_new QCursor (#_Qt::WaitCursor)))
                 (chirp:statuses/update (#_text status))
               (error (err)
                 (#_QMessageBox::critical client "Error!" (format NIL "Failed to tweet: ~a" err)))
               (:no-error (&rest args)
                 (declare (ignore args))
                 (#_setText status "")))
             (#_setCursor client (#_new QCursor (#_Qt::ArrowCursor))))
             (#_QMessageBox::information client "Huh?" "Tweet must be between 1 and 140 characters long!"))))

    Here we have a simple check to make sure the status has the allowed length (chirp takes care of URLs for us), sends out a new status update, and handles the potential errors. Simple, verbose stuff. Looking at our main window now

    (with-main-window (w (make-instance 'client)))

    We'll be able to send tweets, but nothing appears in the list. For that we need to cast some more advanced spells. To handle adding new items to our list we'll define our own signal and slot.

    (define-signal (client new-tweet) (string string))
    (define-slot (client new-tweet) ((user string) (status-text string))
      (declare (connected client (new-tweet string string)))
      (format T "~&Got new tweet from ~a: ~s" user status-text)
      (#_addItem timeline (format NIL "@~a: ~a" user status-text)))

    As you can see, the signal definition holds a type argument list. We'll want to transmit the username and the status text and connect the slot to the widget itself. We'll use that to emit the signal once we get new tweets.

    Since the main thread will be occupied with the UI we need to launch an additional thread to take care of incoming tweets. However, we also need to make sure that the thread shuts down with the UI as well and only launches after the UI is already available. To do this we'll define a general launch function.

    (defun main ()
      (let ((thread))
        (with-main-window (w (make-instance 'client))
          (setf thread
                 #'(lambda ()
                      :user #'(lambda (message)
                                (when thread
                                  (process-message message w) T)))
                     (format T "~&Shutting down tweet stream"))
                 :initial-bindings  `((*standard-output* . ,*standard-output*)))))
        (setf thread NIL)))

    Aside from the with-main-window form, the guts here is the start-stream chirp function which will handle stream communication for us for as long as messages come through and our handler function returns with a non-NIL value. Thus we can check for thread termination and let everything clean up nicely once the UI exits. However, this makes use of one function we haven't defined yet, process-message. Let's change that.

    (defun process-message (message client)
      (format T "~&Message: ~a" message)
      (when (typep message 'chirp:status)
        (signal! client (new-tweet string string)
                 (chirp:screen-name (chirp:user message))
                 (chirp:xml-decode (chirp:text-with-expanded-urls message)))))

    Here we emit a signal to our client using the new-tweet signal and the mentioned arguments. Chirp takes care of URLs and entities. If you launch the client now using the main function, you should see your own status update, as well as everything that happens on your home timeline. That means we're pretty much done already! As a final addition, let's make the main also handle logging in.

    (defun main ()
      (unless *logged-in*
        (with-main-window (w (make-instance 'login))))
      (when *logged-in*
        (let ((thread))
          (with-main-window (w (make-instance 'client))
            (setf thread
                   #'(lambda ()
                        :user #'(lambda (message)
                                  (when thread
                                    (process-message message w) T)))
                       (format T "~&Shutting down tweet stream"))
                   :initial-bindings  `((*standard-output* . ,*standard-output*)))))
          (setf thread NIL))))

    Aaand done, ship it.

    There isn't much else to the general concepts of UI programming with Qt other than widgets, signals, and slots. Everything else lies in knowing about the respective classes and methods, which is more vocabulary than concept. However, I hope that this quick introduction proved interesting and neat enough for you to take making UIs with Common Lisp into your list of feasible things.

    I'd always welcome suggestions and ideas for extensions or modifications to Qtools to make working with Qt even more lispy than it is currently.

    Thank you for your time.

    You may read the source code in one piece here.

    Additional note for the curious: You might be wondering how this all works in combination with Qt. As you know from your C/C++ experience, it uses different method naming conventions and types and all that wahoo. And indeed, the culprit for hiding this from you is Qtools. It translates types and method names into their C++ equivalents behind your back. This goes a long way towards bridging the gap. As an exercise, we'll take a look at the entire transformation sequence of a simple slot definition.

    (define-slot (widget foo) ((text string))
      (print text))

    The first thing that happens is that Qtools translates this into (surprise!) a method definition:

    (defmethod %widget-slot-foo ((widget widget) (text string))
      (declare (slot foo (string)))
      (with-slots-bound (widget widget)
        (print text)))

    Here we see another instance of using declarations to bridge the gap. You can of course also use defmethod directly if you prefer, and for some scenarios you really might. This also reveals why we need to :use cl+qt rather than cl, since Qtools needs to shadow the default defmethod. However, no worries, you can still use it as normal, the only difference is the extra declaration handling. Now, this method definition needs to be purified, as CL itself won't accept the slot declaration:

      (eval-when (:compile-toplevel :load-toplevel :execute)
        (progn (set-widget-class-option 'widget :slots '("foo(const QString&)" %widget-slot-foo))))
      (cl:defmethod %widget-slot-foo ((widget widget) (text string))
        (with-slots-bound (widget widget)
          (print text)))

    And even more interesting things happened now! First what you see is Qtools' widget external redefinition capabilities. Using set-widget-class-option we can change the class definition form of the widget outside of its define-widget form. In this case we set a new :slot value (which is a CommonQt qt-class option). Here we also see that Qtools correctly translated the name and arguments of our slot definition into the equivalent name for the C++ side and links it to the method we define. The method that remains is a standard CL method definition. The with-slots-bound is a special form that performs a with-slots on all available slots of the class. Subwidgets get translated to class slots and using with-slots-bound they become automatically available through their respective symbols. This was added mostly because using accessors to refer to subwidgets becomes so ludicrously tedious, repetitive, and verbose that binding them all by default is the much less painful alternative.

    Qtools offers quite a bit more than is outlined here such as additional type translation, menu definition, and finalization to name some. Take a look at the docs to see what it has in store.

    Quicklisp newsJanuary 2015 download stats

    · 77 days ago
    Here are the top 100 downloads for last month:

    5231 alexandria
    3821 cl-ppcre
    3799 trivial-features
    3664 babel
    3050 cffi
    2923 cl-fad
    2848 closer-mop
    2821 flexi-streams
    2770 slime
    2765 bordeaux-threads
    2632 iterate
    2631 trivial-gray-streams
    2629 trivial-garbage
    2276 split-sequence
    2221 named-readtables
    2172 chunga
    2147 anaphora
    2024 local-time
    1972 usocket
    1965 cl+ssl
    1931 md5
    1849 cl-base64
    1812 trivial-backtrace
    1573 metabang-bind
    1567 nibbles
    1531 ironclad
    1517 drakma
    1511 hunchentoot
    1429 puri
    1389 trivial-types
    1360 let-plus
    1282 cl-unicode
    1261 rfc2388
    1255 cl-syntax
    1245 chipz
    1235 cl-colors
    1184 cl-annot
    1171 cl-ansi-text
    1106 trivial-utf-8
    1074 optima
    1068 cl-interpol
    1057 cl-utilities
    1032 prove
    978 postmodern
    956 log4cl
    912 stefil
    897 cl-json
    871 quicklisp-slime-helper
    797 st-json
    787 parse-number
    753 cl-marshal
    692 fast-http
    674 http-body
    674 cl-sqlite
    668 cl-who
    656 osicat
    646 trivial-mimes
    610 circular-streams
    584 xsubseq
    576 quri
    571 trivial-arguments
    571 fiveam
    544 clack
    543 clx
    538 iolib
    536 salza2
    528 lparallel
    484 cl-dbi
    482 ieee-floats
    482 sxql
    464 parenscript
    454 closure-common
    448 symbol-munger
    447 asdf-system-connections
    437 fare-utils
    436 cl-opengl
    428 cxml
    409 cl-containers
    397 uuid
    395 metatilities-base
    391 static-vectors
    385 zpb-ttf
    373 yason
    369 html-template
    362 buildapp
    360 fare-quasiquote
    355 vecto
    351 ningle
    351 fast-io
    337 cl-yacc
    337 cl-async
    330 cl-vectors
    324 esrap
    319 command-line-arguments
    317 zpng
    313 do-urlencode
    310 myway
    309 map-set
    301 arnesi
    301 external-program

    Nicolas HafnerRunning Tests in CL - Confession 48

    · 79 days ago

    header I haven't come across this anywhere yet, but I think it's worth writing a quick entry about, just so that it's referable. So, writing tests is a common enough occurrence in programming and Common Lisp is no exception. The vast amount of testing frameworks is both a sign of the repeated desire to have a comfortable way to write tests and the general ‘I can do it better’ syndrome prevalent in Common Lisp. However, this blog is not about those things, but about another, much easier aspect: Running tests.

    Having an easy way to run your tests, possibly even automated, is great. Most frameworks don't go into that, so the first instinct of any test writer is to just dump all tests into a file and have a function to run them. Hopefully the tests will be segregated into their own package or system. Still, it's far less than stellar to have to know what the test system is called, load it manually and then run some project-specific test function.

    Luckily, if you're using ASDF for your systems there's a way to make this all streamlined and convenient. The first thing you will want to do is define a separate system for your tests that depends on whatever testing framework you use and the system to test, of course. That way the tests won't have to be loaded if the user doesn't need them. Then, in the system definition of your main project you add a new property to connect the two:

    (asdf:defsystem my-system
      :in-order-to ((asdf:test-op (asdf:test-op :test-system))))

    What this does is tell ASDF that if you perform the test-op on your system, it will delegate that to calling test-op on :test-system, which should be adapted to whatever you named your test system, naturally. This means that you can now call (asdf:test-system :my-system) and have it automatically load and test your proper test system. But, we aren't quite there yet, there's one last thing we need to do, which is to tell ASDF how to execute our test suite.

    In order to do this we'll need a method on asdf:perform, the function responsible for performing any kind of ASDF operation on a component or system. This method definition should be in the source of your test system and can either call or directly replace your main test function:

    (defmethod asdf:perform ((op asdf:test-op) (sys (eql (asdf:find-system :test-system))))

    Once that's in, you can freely call asdf:test-system and it should just work. Doing it this way is beneficial both because it gives users a streamlined interface to perform tests and because it is neatly integrated with the rest of the build system and thus automatable.

    Happy testing!

    Edit: As Orivej Desh helpfully pointed out to me in an e-mail, there's an alternative way to link the test-op to your test running function. Instead of adding the defmethod you can add a :perform property to your test system:

    (asdf:defsystem test-system
      :perform (asdf:test-op (o c) (uiop:symbol-call :test-system-package :run-tests)))

    Seeing this, there's yet another alternative of doing things, which is to put everything into your main system:

    (asdf:defsystem my-system
      :in-order-to ((asdf:test-op (asdf:load-op :test-system)))
      :perform (asdf:test-op (o c) (uiop:symbol-call :test-system-package :run-tests)))

    However, I'm not a fan of this last approach as it requires you to put information of the test system (the name of the main test function) into your main system. Using the :perform property in your test system is definitely a cleaner way to do it than to add your custom defmethod though.

    Quicklisp newsSome problems when adding libraries to Quicklisp

    · 79 days ago
    Here are a few of the problems I encounter when trying to add a library to Quicklisp, as well as how to prevent or fix them.

    Library does not build without warnings. As mentioned a little while ago, ql:quickload normally muffles warnings, even, unfortunately, for non-Quicklisp projects. The Quicklisp dist build environment does not muffle any warnings, and any that occur will break the build for the library. Make sure you use the :verbose t option to ql:quickload to see any warnings that crop up during compilation.

    Library does not build at all.
     I think this happens when someone sees a library that seems cool, they find it is absent from Quicklisp, and they request its addition without trying it first. Please try it first! It's easy to try libraries: fetch the code, put it into ~/quicklisp/local-projects/, look for *.asd files, and use ql:quickload to load one. If it doesn't load, it may prove difficult for me to try to add it to Quicklisp. And if it doesn't have *.asd files, I can't add it to Quicklisp at all.

    Library is missing critical metadata. Make sure the library has :author, :description, and :license in each ASDF system definition.

    Library depends on another library that is not available in Quicklisp. It's fine to request the addition of multiple related libraries. It helps if you specify the order in which they need to be added to work.

    Library system name conflicts with existing system. This happens sometimes when a library bundles its own private copy of a library already present in Quicklisp. In that case, it is usually best to unbundle the private copy, but I can also work around it on my end if necessary. Conflict also happens when someone just doesn't know that a system name is already in use. To check for conflicts, use (ql-dist:provided-systems t) to get a list of existing systems in Quicklisp.

    Zach BeaneYour annual plug for

    · 79 days ago

    Inspired by, I made in 2008 to make it easy to link to the Common Lisp HyperSpec. The HyperSpec is fantastic work, but the URLs are not all that memorable (with good reason). Its canonical location has also occasionally changed. It was once hosted on Xanalys’s website, but now it’s on, and although it seems unlikely, it may move again in the future. has memorable links. will take you to the page in the CLHS that defines “car”. will take you to section, Constraints on the COMMON-LISP Package for Conforming Programs. will take you to the glossary entry for “function designator”. 

    I intend to host and maintain indefinitely. If the CLHS moves from LispWorks to some other domain, will be updated to match. (If, in the future, I can no longer host or maintain it, the source code is on github, and I would be happy to transfer the domain to someone new.)

    If you want to link to CL stuff, consider using

    LispjobsKnowledge Engineer II, Verisk Health, Durham, NC

    · 80 days ago

    Verisk Health builds a smarter healthcare ecosystem through analytics. Our 1,500+ global professionals work at the intersection of high tech, healthcare, and "big data" in order to realize audacious aspirations for our healthcare system. Be it eliminating fraud, waste, and abuse; guiding population health management with data-driven insights; improving revenue cycles for our clients; or re-envisioning support systems for new models of healthcare delivery, we hold ourselves to a single standard: having immediate and outsized impact for our clients, and by extension, the broader health community.  To find out more about us click on the link below.





    • 4 yr. college degree majoring in Computer Science, Electrical Engineering, or related field.
    • 5 yr. experience as a full time professional software developer designing and building both system-level and application software using ANSI Common Lisp required.
    • 5 yr. experience with expert system development, employing both forward and backward chaining rule systems required.
    • 3 yr. experience building CLOS based object-oriented and knowledge-based systems required.
    • 3 yr. experience building practical applications of Artificial Intelligence required.
    • 5 yr. experience following a structured Software Development Methodology that has a defined software development life-cycle required; with recent Agile experience preferred.
    • 3 yr. experience with Source Control Management software required, CVS or Subversion is preferred.
    • 1 yr. experience working with natural language authoring environments preferred.
    • 2 yr. experience building Ontologies preferred.
    • 2 yr. experience writing and refining software requirements and experience writing and developing from software requirements required.
    • 1 yr. experience using Oracle and writing SQL is preferred.
    • Excellent verbal and written communication skills required.
    • Experience with object oriented programming and design required.


    Principle Responsibilities and Essential Duties:


    • Updates job knowledge by researching new technologies and software products; participating in educational opportunities; reading professional publications; maintaining personal networks; participating in professional organizations.
    • Implements new features and change requests based on requirements and technical design specifications.
    • Unit tests software.  Architects and designs new software functionality.
    • Triage, debugs and troubleshoots software issues.  Participates in code reviews by reviewing and providing feedback of others work.
    • Creates software system and integration test plans.  Executes software test plans for system and integration testing.
    • Release Management: builds and packages releases for deployment.
    • Creates technical documentation: software requirements and technical design specifications.

    Marco AntoniottiOpen parenthesis

    · 80 days ago
    It has been a year since I posted something about Common Lisp.  What have I been doing meanwhile on this front?  Well, not much visible, but I am still ill from NIH syndrome, therefore I have been cooking up a few things, while doing my real work ;)
    In any case, the most time consuming things in my corner of the Common Lisp world have been:
    • Moving repos from CVS to git and getting the new to agree with me (or me with it: you decide).  Some new things have been deployed on Sourceforge as I had a very old account there.
    • Fixing HEΛP to ensure that it worked nicely in most implementations and Quicklisp.
    • Building a new library called CLAST (Common Lisp Abstract Syntax Trees; reminder of "clastic rocks") that will do TRT according to my personal tastes; this library will play a role in my rebuilding of CLAZY and other little things.
    Stay tuned.


    For older items, see the Planet Lisp Archives.

    Last updated: 2015-04-14 13:41