Monday, August 25, 2008

Making a small Common Lisp Project (in Cusp)

In honor of my recent addition to Planet Lisp, and as a special thank you to Xach, I figured I'd counter-blog his old post on how to make a lisp project (in Slime). You can go read that if you want. Here's the Cusp way:

Make the project. Go to New > Lisp Project. Enter the name of your project. You're done.

Write the code. You'll notice that a file named "main.lisp" has been opened for you. Put your lisp code there. You can compile the definitions as you write them (with Alt+C), but that's mostly a vestigial holdover from Slime. Cusp is smart. Save your file and it will automatically compile any new or changed top-level forms. (It'll even undefine functions that you've deleted.)

Later on... If you close Cusp, when you come back you'll need to reload the project. To do this, right-click on the .asd file in the project, and choose "Load Project." You may also need to change the package in the REPL to match the one for this project.



So what is all this stuff?


You've got all you need to start hacking, but you probably want to know what's going on behind the scenes. The New Project wizard creates a project folder with three files in it: main.lisp, defpackage.lisp, and [project name].asd. Here's what they do:

main.lisp is the main code file. Put the guts of your program here. You can, of course, create additional files as your project grows. More on that in a moment.

defpackage.lisp defines the package for this lisp project, which is basically the lisp equivalent of a namespace. You could pollute cl-user with your project internals, but that's just asking for trouble down the line. You'll note that main.lisp started out with (in-package :[project-name]). You'll want to make sure any new files you add start that way, too.

If you want to import symbols from another package into your project (so you can say split rather than cl-ppcre:split) put the name of that package into the :use section. This is similar to using in C++ or C#, or import in Java. If your project turns into a library to be used by other projects, you would put any exported symbols into the :export section. Notice that by default, you are already importing :cl.

[project-name].asd is best thought of as your project file. This tells Lisp what libraries to load up for your project, and what files are part of your project. You'll notice that defpackage and main are already listed in the :components section. If you add more files to your project, make sure to tack them on to the end of that list. Files will be loaded in the order they are listed.

Dependencies are also handled by the asd file. If, as in the earlier example, you want to use cl-ppcre, make sure to add it to the :depends-on section.

Asd files can get more complicated if you need, but this should be enough to take care of you in 95% of all cases. Happy hacking!

Monday, August 18, 2008

Unit Tests (Alpha)

Some of the other developers are currently working on integrating unit testing into Cusp. It's a project I'm not personally involved in, but I'm rather excited about. Up until now, the bulk of Cusp development has consisted of putting existing Slime functionality into a more sane and usable UI. With this one, we'll be breaking entirely new ground.

Things are still in the very early stages, so if you want to contribute code, ideas, or just see how the current plans are shaping up, you can check out the thread.

In which I mention that I like macros

Lest this blog be limited only to complaining about Lisp's shortcomings, allow me to take moment to sing the praises of macros, one of the greatest language features that's probably not even possible in other syntaxes.

Recently, I had to write a program to scrape a bunch of data off of a few thousand web pages. My general pattern was to skip forward until I found a certain string, then skip forward a bit more and grab whatever was between certain tags. It was also important to leave the cursor at the end of wherever I had searched, so that the next bit of data I scraped out would start looking at that point. This particular mutation made a function not terribly well suited to the task.

This came out to roughly ten lines of code per field searched for. But it was trivial to put those into a macro, and turn all my scrapes into something along the lines of (after-and-between phone "Phone:" "<b>" "<br").

The macro facility is one I especially miss when I'm programming Cusp (in Java, naturally). In the SwankInterface class, I have several dozen functions which all start with identical code to register a callback, and all end by calling a function to send a string to Swank. It's only 2 lines per function, but now that I'm used to Lisp, those lines annoy me. It's wasteful, and what if I have to change them someday?

Just one of the ways in which Lisp ruins other languages for you. CLOS makes things even worse.

Tuesday, August 12, 2008

The Library Problem

Today, I got a new task which involved scraping some web pages. Obviously, as part of this I needed a library to download the pages in question, so I asked around1 and was pointed to Drakma. It's Weitz-ware, so you can count on it to be reliable and well-documented, so I downloaded it.

Trying to load it did not go so well. I discovered that I needed a few dependencies. Some I had already, but I still had to go back and download Chunga (oddly, Wietz said to get 0.5.0 or higher, even though it's only up to 0.4.3, and he's the one who wrote Chunga2), and usocket, and a newer puri, and a newer cl-base64, and CL+SSL. CL+SSL was especially fun, because it's one of those libraries that says to pull it from cvs rather than use the tarball. Alas, the cvs command they provided utterly failed to work for me, so I went with the tarball anyway.

Once I had all those unzipped into my libraries folder, I tried again. FAILURE. It turns out that these dependencies had dependencies of their own. CFFI seemed to be called for. So I went to the CFFI download page, got it, and found that it had three more dependencies of its own.

Babel and trivial-features were easy enough downloads, but then I got to Alexandria. Alexandria has not yet made a real release. You have to pull it from the repository. But it's even better than that, because the repository is darcs, a version control system that pretty much nobody uses. In my case, I had to first install darcs just so I would be able to get this dependency that was 3 or 4 levels removed from the library I was actually interested in.

All told, it looks like I downloaded at least 9 additional libraries, one of which involved installing special software I have no need for. So Common Lisp definitely does have a library problem, but it's not the one a lot of people think it is. I've always been able to find a library that provides me with the functionality I need. The library problem lies in the fact that I need to download 20 other libraries, often through their versioning systems, in order to get that one to work.

Happily, this is a problem I'm in a good position to help with, since I'm already distributing a ready-to-use lisp system. As you may have noticed, Cusp comes with a number of popular lisp libraries already installed. The "Load Package" dialog even gives descriptions of what some of them are for, thanks to Sergey's work. Obviously, though, there are a lot more libraries I still need to include. It's a wonder I put up with this sort of thing when I was a newb.

So, I think packaging libraries will be a higher priority for the next release. And if somebody could make an asdf-install for sbcl that will work on windows, they will have my hearty thanks.


1s/around/one guy
2Don't laugh, though. His documentation is still way better than yours.