So I have tried my hands at socket programming in Common Lisp lately, using the (widely used) usocket library.
After getting past the initial difficulties of learning how to use the library’s API (thanks to various tutorials & guides, especially this one by Sid Heroor), I’ve noticed that many people recommend using the
with-* macros (specifically,
with-socket-listener) provided by usocket for the sake of convenience (these macros will ensure that errors are properly handled and all sockets are properly closed after we are done with them) and clarity.
Well, the only problem is that I can’t seem to find any guide or tutorial on how to use them. After searching in vain for a couple of hours, I decided to just bite the bullet and dive into usocket’s source code to see how these macros work, and, to my surprise and delight, found that these macros are very easy to understand.
Basically, all the other
with-* macros are built on top of the
with-connected-socket macro. The
with-connected-socket macro is responsible for automatically binding a socket to a variable, passing the body to the
with-mapped-conditions helper macro which handles any errors or exceptions, and ensuring that the socket is destroyed on exit. The
with-client-socket macro provides a nice and convenient interface over the
socket-connect function for a client to connect to a server. It not only automatically binds a socket to a variable, but also creates a socket stream for the client as well. The
with-socket-listener macro provides a convenient interface over the
socket-listen function, and returns the resulting socket to the
with-server-socket macro. The
with-server-socket macro, in turn, passes the socket that was created from the call to
socket-listen to the
We can rewrite the example by Mr. Sid using these
with-* macros as follows:
Note how these macros combined can significantly reduce boilerplate code in both the server and client, as well as making the program safer and easier to understand. This is a great example of the power of Common Lisp’s macro. In other languages, for example Python, it would require a new version of the language to introduce the equivalents of the
with-* macros seen here, while in Lisp one can introduce a new control structure/expression as a part of a library! I also love how the definitions of the
with-* macros themselves serve as a quasi-style guide on how to safely use the underlining functions of usocket.
Again, Common Lisp (as well as other Lisp dialects) continues to impress me, and I look forward to learning more about the language.