Deprecated: Function get_magic_quotes_gpc() is deprecated in /home/didierve/didierverna.net/blog/inc/libs/clearbricks/common/lib.http.php on line 410

Deprecated: Function get_magic_quotes_gpc() is deprecated in /home/didierve/didierverna.net/blog/inc/libs/clearbricks/common/lib.http.php on line 410
Lisp - Didier Verna's Scientific Blog - page 4
About Lectures Research Software Blog
Musical Site
MySpace
Facebook

Moods Blog

Dojo Shin Kaï

RSS Feed
Thank you!

XHTML 1.0 conformant
CSS 2.0 conformant
Didier Verna's scientific blog: Lisp, Emacs, LaTeX and random stuff.

Wednesday, June 29 2011

Declt 1.0b12 is out

I've just released the next version of Declt, my reference manual generator for ASDF systems.

This release includes some fixes for the Info format target but most notably, support for documenting (generic) writer functions and methods. When it makes sense, the documentations for func and (setf func) are grouped together. Getting closer to an official 1.0 stable version...

Grab it here, and enjoy!

Tuesday, June 21 2011

read-time string concatenation

Sometimes, I miss the string concatenation capability of C. I mean, the way that you can split a long string into smaller ones and have them automatically concatenated together. The format function has a tilde (~) directive that does something along these lines, but there are two problems:

  • first, I'm not necessarily facing the problem in format calls,
  • next, my favorite text editor cannot properly indent the string contents when I press the TAB key.

Here's an example:

(defclass sample ()
  ((slot :documentation
	 "A very long slot documentation, that doesn't even fit in 80 columns, which is a shame...")))

If that were C code, I could write this:

(defclass sample ()
  ((slot :documentation
	 "A very long slot documentation, "
	 "that doesn't even fit in 80 columns, "
	 "which is a shame...")))

But (thank God) this is not C code. We can come very close to that however. Here's a small reader function that will automatically concatenate strings prefixed with a tilde (~) character (in honor of format's directive):

(defun tilde-reader (stream char)
  "Read a series of ~\"string\" to be concatenated together."
  (declare (ignore char))
  (flet ((read-string (&aux (string (read stream t nil t)))
	   (check-type string string "a string")
	   string))
    (apply #'concatenate 'string
	   (read-string)
	   (loop :while (char= (peek-char t stream nil nil t) #\~)
		 :do (read-char stream t nil t)
		 :collect (read-string)))))

Let's add it to the current readtable:

(set-macro-character #\~ #'tilde-reader)

And now I can write this:

(defclass sample ()
  ((slot :documentation
	 ~"A very long slot documentation, "
	 ~"that doesn't even fit in 80 columns, "
	 ~"which is a shame...")))

Everyday of my life I thank Common Lisp for being so flexible. The next step would be to make cl-indent.el aware that tilde-strings really are the same object, and hence should be vertically aligned in all contexts. I'm not there yet. Jeeze, this indentation hacking will never end... :-)

Tuesday, May 31 2011

Declt 1.0b11 is out

I've just released a new version of Declt, my Texinfo reference manual generator for ASDF systems. This release contains only one bugfix: when trying to create links to source files, Declt now checks whether the files actually exist or not.

Tracking this bug down had the side-effect of exhibiting a misfeature of SBCL's introspection facility: the COPY-<struct> functions (automatically generated by defstruct calls) have their definition source set to target-defstruct.lisp which is an SBCL source file. It would make more sense to set it to the file containing the defstruct call instead, as is already the case for constructors, predicates and accessor functions. Patch sent to the SBCL developers.

Monday, May 30 2011

European Lisp Symposium in-between

It's been two months since ELS 2011 is over and I didn't have the time to give my impressions as the programme chair until now. I still don't have much time, so it's going to be quick, but before that, here are two announcements in this transition phase:

  • the proceedings are now available as a single PDF file.
  • eventhough a couple of options are already under consideration, we are still looking for volunteers to be next year's local chair. If this is of interest to you and you have the ability to locate ELS 2012 at your place, please contact us.

About ELS 2011 now. I'd say that it was a great success, perhaps the most successful of the 4 occurrences. We got two full days of interesting talks on various topics and of different forms. We gathered more than 60 persons from all around Europe and also a quite a few from the US (ITA contributed greatly to that :-). The final panel was very nice (something quite rare these days). The local organization went also pretty smoothly.

In retrospect, and as the person in charge of the contents, I have several hypothesis on what makes such an event successful, especially in those days where academic events suffer from a decreasing level of attendance.

  1. Having a "special focus" helps. Having an important one (like Parallelism and Efficiency) helps even more.
  2. Having a regularly occurring event also helps a lot, especially for academicians. This is not new, but it really is important to know that ELS will always happen roughly at the same period every year. Academicians (at least) need to plan their work that long in advance.
  3. I also like more and more the formula of a "mixed" conference where you invite formal (technical) papers, demonstrations, position papers etc. Some people know how to write technical papers, some people don't, are not so good at it, or just don't have the time for it, but it doesn't mean they have nothing interesting to say. ELS 2011 had about 50% formal presentations and 50% demonstrations. I decided to create the different sessions not by grouping talks based on format, but based on topic, and I think this went pretty well. The sessions didn't look completely heterogeneous to me.
  4. Having invited speakers helps. This is of course not new at all, but here, I would just like to answer something I've read recently about ELS 2011; a blogger (I don't remember who) saying that he didn't understand why 2 out of the 3 guests were not speaking about Lisp at all. My opinion on this is simple: as a community (in general; not speaking of Lisp in particular), we have a tendency to be separated from the rest of the CS crowd and loose track of what's going on next door. We don't talk to each other enough. Hell, it's already so difficult to stay up-to-date with your own crowd sometimes! So when I attend a very focused conference, like a language-specific one, I'm always happy to be served a couple of talks that can broaden my view of things, even if they have no direct connection with my own activities. In our specific case, I was very happy with Craig Zilles'presentation and I can see how this could be of interest to us in the long term.

So, that's it for now. Stay tuned for next year's location, and in the meantime, remember that some other Lisp events are already planned: ECLM in Amsterdam, and ILC in Kyoto... simply my favorite place in the world!

Friday, May 6 2011

Common Lisp indentation in XEmacs

UPDATE: since the original publication of this blog entry, Nikodemus Siivola and I have done some more work on various other aspects of Common Lisp indentation, and I must say that the result is pretty satisfactory. Nikodemus has merged all the changes into Slime, and I have done so for XEmacs. If you're an XEmacs user, you don't need to use the slime-indentation contrib to get these improvements. Simply upgrade the "prog-modes" package and load cl-indent.el.

I have just modified XEmacs to improve the indentation of Common Lisp code. This change involves two things: the support for multiple method qualifiers in a call to defmethod and, much more importantly, a cleaner and more flexible scheme for indenting lambda lists. The patch has also been submitted to the GNU Emacs developers. Below is a more detailed description of what you get with these changes.

Method qualifiers

Until now, only one method qualifier was understood. Below are some examples demonstrating that the one method qualifier and the argument list are indented by 4 characters, and the method's body only by 2:

(defmethod foo :around ()        (defmethod foo :around
  do-this)                           ()
                                   do-this)
(defmethod foo
    :around ()                   (defmethod foo
  do-this)                           :around
                                     ()
                                   do-this)

Now let's add a second method qualifier:

(defmethod foo comb :around ()        (defmethod foo	    
	   do-this)			  comb :around () 
					  do-this)

Woops. Neither is correct. But now, you get this instead:

(defmethod foo comb :around ()        (defmethod foo	    
  do-this)				  comb :around () 
					do-this)

Three more examples to show how confused we were:

(defmethod foo comb :around     (defmethod foo comb     (defmethod foo 
  ()				    :around		    comb       
  do-this)			  ()			    :around    
				  do-this)		  ()	       
							  do-this)

And how better we just got:

(defmethod foo comb :around     (defmethod foo comb     (defmethod foo
    ()				    :around		    comb      
  do-this)			    ()			    :around   
				  do-this)		    ()	      
							  do-this)

Indeed, you can see that everything between the method's name and its body is now correctly indented by 4.

Lambda Lists

The next round of changes deals with the formatting of lambda-lists. As such, this will apply everywhere a lambda-list is expected, such as defun, defgeneric, defmethod etc. First of all, here are two examples showing that we were not very clever before:

(defun foo (mand1 mand2
	    &optional opt1
	    opt2
	    &rest args
	    &key key1 key2
	    (key3 val3) &aux aux1
	    aux2)
  do-this)

(defun foo (mand1 mand2 &optional opt1
	    opt2
	    &rest args
	    &key key1 key2
	    (key3 val3) &aux aux1
	    aux2)
  do-this)

Basically, everything was blindly aligned at the beginning of the lambda-list. Here is what you get now:

(defun foo (mand1 mand2
	    &optional opt1
	      opt2
	    &rest args
	    &key key1 key2
	      (key3 val3) &aux aux1
			    aux2)
  do-this)

(defun foo (mand1 mand2 &optional opt1
			  opt2
	    &rest args
	    &key key1 key2
	      (key3 val3) &aux aux1
			    aux2)
  do-this)

The difference is that keyword parameters are indented with respect to their corresponding keyword. The amount of indentation is provided by a new customizable user option named lisp-lambda-list-keyword-parameter-indentation (oh boy, what a mouthful). If you prefer, you can also have the parameters vertically aligned with each other. Set the new customizable user option named lisp-lambda-list-keyword-parameter-alignment to t and you will get this instead:

(defun foo (mand1 mand2
	    &optional opt1
		      opt2
	    &rest args
	    &key key1 key2
		 (key3 val3) &aux aux1
				  aux2)
  do-this)

(defun foo (mand1 mand2 &optional opt1
				  opt2
	    &rest args
	    &key key1 key2
		 (key3 val3) &aux aux1
				  aux2)
  do-this)

Finally, just as you could align keyword parameters together, you can also align the keywords together. Set the new customizable user option named lisp-lambda-list-keyword-alignment to t, and you will get this (only the second example differs):

(defun foo (mand1 mand2 &optional opt1
				  opt2
			&rest args
			&key key1 key2
			     (key3 val3) &aux aux1
					      aux2)
  do-this)

These are in fact my preferred settings, although both alignment options default to nil. Here is a final example demonstrating how you could format a long lambda-list with plenty of arguments:

(defun foo (mand1 mand2
	    &optional
	      opt1 opt2 opt3
	    &key
	      key1 key2 key3
	    &aux
	      aux1 aux2 aux3)
  do-this)

These indentation problems have been a huge peeve of mine for quite a long time. I hope you will find the changes useful!

Tuesday, April 26 2011

ASDF-FLV and a new CDR proposal

UPDATE: the CDR proposal corresponding to this blog is now finalized. It can be referred to as CDR #9.

In my ELS 2011 lightning talk, I announced the development of a new Common Lisp library called XFormat, which provides extensible format strings. A first release of this library is imminent. In this talk, I also mentionned the need for what I called "file-local variables". A file-local variable is a user-defined special variable that would behave as *PACKAGE* and *READTABLE* with respect to *LOAD* and *COMPILE-FILE*.

I have just created and released a very small library called ASDF-FLV which provides file-local variables through ASDF. In an ideal world, this library would become obsolete because file-local variables are so simple to implement that they should rather be done as an extension to the Common Lisp Standard, and provided by every Lisp vendor. That is the purpose of a new CDR proposal that I also just published on the discussion mailing list. This proposal is attached below for reference (update: it is now the final version).

Friday, April 1 2011

[CfP] DLS 2011: the 7th Dynamic Languages Symposium

Dynamic Languages Symposium 2011

Co-located with SPLASH 2011 In association with ACM SIGPLAN

Portland, Oregon, USA, October 24, 2011

http://www.dynamic-languages-symposium.org/dls-11/

Call for papers

The 7th Dynamic Languages Symposium (DLS) at SPLASH 2011 is a forum for discussion of dynamic languages, their implementation and application. While mature dynamic languages including Smalltalk, Lisp, Scheme, Self, Prolog, and APL continue to grow and inspire new converts, a new generation of dynamic scripting languages such as Python, Ruby, PHP, Tcl, Lua, and JavaScript are successful in a wide range of applications. DLS provides a place for researchers and practitioners to come together and share their knowledge, experience, and ideas for future research and development.

DLS 2011 invites high quality papers reporting original research, innovative contributions or experience related to dynamic languages, their implementation and application. Accepted Papers will be published in the ACM Digital Library.

Areas of interest include but are not limited to:

  • Innovative language features and implementation techniques
  • Development and platform support, tools
  • Interesting applications
  • Domain-oriented programming
  • Very late binding, dynamic composition, and runtime adaptation
  • Reflection and meta-programming
  • Software evolution
  • Language symbiosis and multi-paradigm languages
  • Dynamic optimization
  • Hardware support
  • Experience reports and case studies
  • Educational approaches and perspectives
  • Object-oriented, aspect-oriented, and context-oriented programming

Submissions and proceedings

We invite original contributions that neither have been published previously nor are under review by other refereed events or publications. Research papers should describe work that advances the current state of the art. Experience papers should be of broad interest and should describe insights gained from substantive practical applications. The program committee will evaluate each contributed paper based on its relevance, significance, clarity, and originality.

Accepted papers will be published in the ACM Digital Library.

Papers are to be submitted electronically in PDF format. Submissions must not exceed 12 pages and need to use the ACM format, templates for which can be found at http://www.acm.org/sigs/pubs/proceed/template.html.

Important dates

Submission of papers: June 17, 2011 (hard deadline) Author notification: July 19, 2011 Final versions due: August 19, 2011 DLS 2011: October 24, 2011 SPLASH 2011: October 22-27, 2011

Program chair

Theo D'Hondt, Software Languages Lab, Vrije Universiteit Brussel, Belgium

Program committee

  • Andrew Black, Portland State University, USA
  • William R. Cook, University of Texas at Austin, USA
  • Marc Feeley, University of Montreal, Canada
  • Roberto Ierusalimschy, PUC-Rio, Brazil
  • Michele Lanza, University of Lugano, Switzerland
  • Hidehiko Masuhara, University of Tokyo, Japan
  • Mira Mezini, University of Darmstadt, Germany
  • Mark Miller, Google, USA
  • Manuel Serrano, INRIA Nice, France
  • Laurence Tratt, Middlesex University, UK
  • David Ungar, IBM, USA
  • Didier Verna, EPITA Research and Development Laboratory, France

Monday, March 21 2011

ELS 2011 last minute addition

Hello all,

I'm pleased to inform you that we have a last minute addition to the 4th European Lisp Symposium's programme: a presentation by Alec Berryman from ITA software about parallelizing an SBCL codebase for performance. I think this will make a perfect introduction to the subsequent panel entitled "Lisp: the next challenges"...

Hope to see you there, still time to register!

Wednesday, March 2 2011

ELS 2011 programme now available!

The final programme for the 4th European Lisp Symposium is now online! 2 full days of keynotes, technical papers, demonstrations, lightning talks and panels with a special focus on performance, efficiency, parallelism, concurrency, distribution...

Early bird registration is still available until March 12th so hurry!

Hope to see you there.

Wednesday, February 23 2011

Declt 1.0b9 is out

The next edition of Declt, the Documentation Extractor from Common Lisp to Texinfo, is out. In this release:

  • Bugfix: rendering the documentation for methods with EQL specializers didn't work.
  • Feature: licensing and copyrighting the reference manual is now optional. Licenses currently supported are BSD and GPL.
  • Declt now generates its own reference manual by default.
  • Some package infrastructure changes that should remain transparent.

Grab it here

Happy documenting!

Tuesday, February 15 2011

Register now to ELS 2011 !

The 4th European Lisp Symposium is now open for registration! See the website for details.

The early registration deadline is March 12. There is also a reduced fee for students and accompanying persons.

The complete program will be available shortly.

Hope to see you there!

Friday, February 11 2011

Clarification proposal for CLHS 22.3

There are some fuzzy corner cases in the way the Common Lisp standard describes the syntax and semantics of FORMAT directives. I have prepared a first draft of a clarification proposal for the relevant parts of the standard, which is attached in PDF format. I'm giving myself some time for comments and feedback before actually submitting this to the Common Document Repository.

Update: this document (in version 1.1) has been submitted and accepted today as a new item in the Common Document Repository. It can now be officially referred to as "CDR 7".

Wednesday, February 9 2011

Clon 1.0b19 is out

Clon version 1.0b19 has just been released. This version comes with a couple of fixes related to error handling and a switch from the GPL to the BSD license. Grab it here.

Tuesday, February 8 2011

Which open source license for Lisp?

It's been a long time since I last thought about this. Software licensing is probably the most dreadful computer science topic to me. So out of boredom, laziness, but also out of a feeling of adherence to the ideas behind the FSF, I used to blindly stick the GNU GPL to most of my code. A couple of things made me rethink about that passive attitude recently though, notably the fact that the viral nature of the GPL is not something that I always want.

Even in Lisp, you can make a difference between (more-or-less) standalone applications and actual language extensions or libraries that other people might want to use in their own code. While I still think that the GPL is okay for my applications (as Pascal Bourguignon would turn it: I want to see your code too!), I find it too restrictive for my libraries. I sympathize with the FSF concerns, and we probably need something so idealistic to make the open source culture progress, but I can also understand why people wanting to make a living out of their development need to close their source. For example, I consider the few proprietary Common Lisp vendors as my friends, and I would be glad to see them use my libraries in their own products.

The other thing with the GPL is that it is long, difficult to read and gives me a feeling of over-complication. Probably just me and my allergy to software licensing issues, but on the other hand, it is notorious that the GPL doesn't fit very well with Lisp, for the same reasons that it doesn't fit very well with C++ code constituted mostly of templates. In those environments, the distinction between static or dynamic linking, compile-time or run-time etc. is blurred to a considerable extend, to the point that it doesn't make much sense anymore.

Choices

So I was ready to spend, say, 30 minutes looking for a non-viral alternative to the GPL. The first one that comes to mind is of course the LGPL, but it looks even more complicated than the GPL itself, and as misfitted to Lisp as its mother. To the point that some people at Franz Inc. created the Lisp Lesser GNU General Public License, a.k.a. the LLGPL. This license is in fact constituted with the original LGPL plus a preamble aimed at clarifying or precising some terms used in the license itself, in the context of Lisp. This preamble left me quite sceptical. While it seems to indeed clarify a few points, I think it also adds to the confusion. For instance, it says at some point:

Since Lisp only offers one choice, which is to link the Library into an executable at build time ...

which I think is confusing. What about a Lisp application that dynamically loads an ASDF system. Shouldn't this be considered as very close to dynamic linking? So no. I want something simpler, widely used and accepted. This leaves me basically with MIT, or BSD style, plus Boost that Daniel Herring suggested on comp.lang.lisp.

The MIT license is probably too liberal for me. It is essentially a big disclaimer but that's all. Also, some words are frightening. For instance, what does sublicensing exactly mean in this context? The Boost one is nice, apart from one thing: it makes acknowledgments optional for binary distribution, and I don't like that. It seems to me that the least you can do when you're using a software component written by someone else is to mention it. It will also help people interested by the feature in question to find its source.

So that leaves me with BSD which I decided to use with a bit of rewording and one specific part removed: the All rights reserved part. I think it doesn't make any sense since the purpose of the license itself is to grant you some rights.

Acknowledgments

Eventhough I find that acknowledgments are important, I don't want it to be a burden on the shoulders of my clicents. One simple way to ease their life is to include the complete license as a header in every single file of your library. The BSD license is so short that it fits nicely in headers (actually, the whole license doesn't take much more space that the GNU GPL header alone). Besides, I use a (never released) XEmacs package for maintaining static file contents automatically, which means that I never have to deal with license contents by hand, not even in new files. For binary distribution, I also include a LICENSE file in my libraries, so that people can just copy it into their own packages and be compliant.

Texinfo files

As for Texinfo files, the copyright material needs some adjustment with respect to the original GNU recommendation. Most notably, I don't need the FSF to approve translations of the copyright notice anymore. I find that the following template fits my needs nicely:

@copying
@quotation
Copyright @copyright{} @value{COPYRIGHT_DATE} Didier Verna

Permission is granted to make and distribute verbatim copies of this
manual provided the copyright notice and this permission notice are
preserved on all copies.

@ignore
Permission is granted to process this file through TeX and print the
results, provided the printed document carries a copying permission
notice identical to this one except for the removal of this paragraph
(this paragraph not being relevant to the printed manual).

@end ignore
Permission is granted to copy and distribute modified versions of this
manual under the conditions for verbatim copying, provided also that the
section entitled ``Copying'' is included exactly as in the original.

Permission is granted to copy and distribute translations of this manual
into another language, under the above conditions for modified versions,
except that this permission notice may be translated as well.
@end quotation
@end copying

So that's it. You can expect most of my Lisp libraries to be released under a BSD style license now.

Tuesday, January 25 2011

Optional ASDF system dependencies (Clon v1.0b18)

Clon v1.0b18 is now out. Compared to the previous version, the only small bit of change is the fact that the CLISP implementation now depends only optionally on cffi, whereas that dependency was mandatory before. Doing this is actually quite simple but raised the question of optional ASDF system dependencies, a topic on which there's quite a bit to be said.

A bit of context first. Clon has a terminal autodetection feature which allows it to automatically highlight its output on a tty (see --clon-highlight=auto) and also compute the output line width in case the COLUNMS environment variable is not set. This feature requires an ioctl call which is beyond Lisp. Since one of my goals is to have as few dependencies as possible (zero being the ideal number), I looked at compiler-specific solutions to this problem. The result is that SBCL, CMU-CL, CCL and ECL provide solutions almost out-of-the-box: SBCL has a grovel contributed module, CMU-CL and CCL already have system bindings and ECL has its own ffi interface. The ABCL port doesn't support terminal autodetection yet, but that's another (Java) story. The only black sheep in the picture is CLISP which, as far as I can tell, neither has a native binding for ioctl, nore any built-in grovel facility, hence the need for cffi.

Previously, my system definition file was like that:

#+clisp (asdf:operate 'asdf:load-op :cffi-grovel)
 
(asdf:defsystem :com.dvlsoft.clon
  #| ... |#
  :depends-on (#+clisp :cffi)
  :components ((:file "package")
			#+clisp
			(:module "clisp"
			   :depends-on ("package")
			   :components ((cffi-grovel:grovel-file "constants")))
			(module "src"
                          :depends-on ("package" #+clisp "clisp")
                          :components #| ... |#)))

And then later, I had a file with the concerned utility function:

(defun stream-line-width (stream)
  #+clisp (#| CLISP implementation |#)
  #| etc. |#)

After that, I started looking at ways to make the dependency on cffi optional. After all, it makes sense to avoid that dependency at the cost of not being able to autodetect terminals.

One thing I fell on almost by accident is ASDF's :weakly-depends-on keyword. Here is an interesting thread about it. It was an accident because that feature is not documented :-( People, however, have very mitigated feelings about it, as shown in this other thread (syntax and semantics both appear somewhat shaky and underspecified). Besides, the aparent behavior is that if A weakly depends on B and B is not present, then A is operated anyway. So I could probably have my "src" module weakly depend on the "clisp" one, but that doesn't change the fact the "clisp" module should not be included at all if cffi is not there.

In the same thread, somebody proposes another kind of dependency called :contigent-on which looks closer to what I would need for the "clisp" module: a module the contingency of which is not present will not be processed. This new kind of dependency doesn't seem to be implemented yet, however.

So, all of this seems a bit frightening. Too borderline for my taste. Fortunately, my solution is much simpler, although probably not universal.

This first thing to do is only attempt to load cffi-grovel:

(eval-when (:load-toplevel :execute)
  #+clisp (handler-case (asdf:operate 'asdf:load-op :cffi-grovel)
	    (asdf:missing-component ()
	      (format *error-output* "~
*********************************************************************
* WARNING: ASDF component CFFI-GROVEL not found.
* Clon will be loaded without support for terminal autodetection.
* See section A.1 of the user manual for more information.
*********************************************************************"))))

After that, if loading it were successful, we end up with cffi as a feature, so we can just conditionalize on that:

(asdf:defsystem :com.dvlsoft.clon
  #| ... |#
  :depends-on (#+(and clisp cffi) :cffi)
  :components ((:file "package")
			#+(and clisp cffi)
			(:module "clisp"
			   :depends-on ("package")
			   :serial t
			   :components ((cffi-grovel:grovel-file "constants")))
			(module "src"
                          :depends-on ("package" #+(and clisp cffi) "clisp")
                          :components #| ... |#)))

One last problem remains however: what to do in the source code, for the feature-dependent parts. Conditionalizing an ASDF system may indeed lead to trouble: for instance, what would happen if the function stream-line-width was compiled with cffi around, and later used in a context where it is not? To be on the safe side, what you really need is to dynamically check for the feature. One possible solution is this:

  1. move all feature-dependent code to the "clisp" module and make that a protocol,
  2. everytime you need to access the feature, dynamically check whether the protocol functions are fbound.

In my specific case, what I did was to implement a CLISP-specific version of stream-line-width, called clisp/stream-line-width and put it in a new file in the "clisp" module, now defined as follows:

#+(and clisp cffi)
	       (:module "clisp"
		 :depends-on ("package")
		 :serial t
		 :components ((cffi-grovel:grovel-file "constants")
					(:file "util")))

Then, the original function is rewritten like this:

(defun stream-line-width (stream)
  #+clisp (when (fboundp 'clisp/stream-line-width) (clisp/stream-line-width stream))
  #| etc. |#)

So now I think I'm on the safe side, and Clon has zero mandatory dependency again...

Monday, January 24 2011

Clon 1.0b17 is out

I'm happy to announce the release of Clon version 1.0b17. This version notably introduces support for ABCL and expands the documentation in the portability section. Grab it here.

Saturday, January 22 2011

Towards ABCL Standalone Executables

UPDATE: ABCL now supports the POSIX-compliant use of --, so I've modified this blog to reflect that. I've also added a final trick to emulate the existence of a proper argv[0].

Creating standalone executables in Common Lisp is already a portability minefield, as the standard doesn't specify anything in that regard. The situation is even worse with ABCL because it is a Java-based implementation of Common Lisp, and Java has no notion of standalone executable at all. In this article, we will try to figure out how far we can go in that direction nevertheless. This work comes from my wish to port Clon to ABCL. In order to make it work, ABCL itself needed some changes, so if you want to try out the code provided below, beware that you need at least revision 13156 from the ABCL Subversion trunk (or version 0.24.0). Let's start by writing a great Common Lisp application for ABCL, and call it greet.lisp:

(defun main ()
  (format t "Hello,~{ ~A~}!~%" extensions:*command-line-argument-list*)
  (extensions:exit :status 0))
 
(main)

As you guessed, extensions:*command-line-argument-list* stores the list of command-line options passed to the program. Now, let's try it out:

$ abcl --noinform --noinit --nosystem --load greet.lisp John Doe
Hello, John Doe!

So far so good: ABCL-specific options were eaten by ABCL. Not very standalone however. Let's create a wrapper script around that, and call it greet:

#! /bin/sh
exec abcl --noinform --noinit --nosystem --load greet.lisp ${1+$@}

In fact, we have a problem:

$ ./greet --help me
Parameters:
--help displays this help
--noinform suppresses the printing of version info
--eval <form> evaluates the <form> before initializing REPL
--load <file> loads the file <file> before initializing REPL
--load-system-file <file> loads the system file <file> before initializing REPL
--batch enables batch mode. The --load, --load-system-file and --eval parameters are handled, and abcl exits without entering REPL
--noinit suppresses loading a .abclrc startup file
--nosystem suppresses loading the system startup file

Woops! We were expecting to get Hello, --help me! weren't we? In other words, our own command-line options may conflict with ABCL's which is not nice. One thing we can do with a recent ABCL version is to use -- to separate ABCL's own command-line arguments from ours. Our script becomes:

#! /bin/sh
exec abcl --noinform --noinit --nosystem --load greet.lisp -- ${1+$@}

And we now get this:

$ ./greet --help me
Hello, --help me!

This is better, although we're not actually very standalone yet: our Lisp file is a separate beast, and the abcl thing is also just a wrapper script (see below). If we want to be more standalone, we will need to go the Java way.

The first thing to understand is that there's actually no such thing as an ABCL executable. ABCL is packed into a JAR (Java archive) file, a zip file, really, and what the wrapper does is simply to call java -jar /path/to/abcl/abcl.jar options... The JAR file contains a Main class with a main function the purpose of which is to launch a Lisp interpreter. This is done by calling the method Interpreter.createDefaultInstance, which, amongst other things, handles the command-line options. There is also a method called Interpreter.createInstance which does not handle the command-line at all, so it seems that this is the one we could use, provided that we find a way to set extensions:*command-line-argument-list* manually.

The following code does exactly this. Let's call it Greet.java.

import org.armedbear.lisp.*;
 
public class Greet
{
    public static void main (final String[] argv)
    {
	Runnable r = new Runnable ()
	    {
		public void run()
		{
		    try
			{
			    LispObject cmdline = Lisp.NIL;
			    for (String arg : argv)
				cmdline = new Cons (arg, cmdline);
			    cmdline.nreverse ();
			    Lisp._COMMAND_LINE_ARGUMENT_LIST_.setSymbolValue (cmdline);
 
			    Interpreter.createInstance ();
			    Load.load ("greet.lisp");
			}
		    catch (ProcessingTerminated e)
			{
			    System.exit (e.getStatus ());
			}
		}
	    };
 
	new Thread (null, r, "interpreter", 4194304L).start();
    }
}

Our Greet class mimics what ABCL's Main class does, only with some tweaks of our own:

  • we build the value of extensions:*command-line-argument-list* manually from the actual argv passed to the function main, by consing equivalent Lisp objects and then reversing the list. That way, we completely bypass ABCL's options processing code.
  • as mentioned earlier, we use Interpreter.createInstance instead of Interpreter.createDefaultInstance.
  • we also take the opportunity to load our lisp file directly with the function Load.load.

Finally, the try/catch construct intercepts calls to extensions:exit and effectively leaves the Java environment.

Let's compile this beast now:

$ javac -cp  /path/to/abcl/abcl.jar Greet.java

The -cp option to javac, the Java compiler, tells it where to find ABCL classes. This command gives us a Greet.class file, but also a second one named Greet$1.class. That's because our code creates an "anonymous inner class", whatever that means, in the Java jargon. Now, how do we bypass ABCL's main function and use or own instead? This is actually very simple. The Java command-line lets you specify (read: override) the name of the class in which to find the main function. So it turns out that we don't even have to modify ABCL itself for this to work. We can simply go:

$ java -cp  /path/to/abcl/abcl.jar:. Greet John Doe
Hello, John Doe!

and it works. By the way, we can also go:

$ java -cp  /path/to/abcl/abcl.jar:. Greet --help me
Hello, --help me!

and see that it still works. Since ABCL doesn't process its command-line anymore, there's no question about -- or whatever. Note that this time, we need to add the current directory to the class path option in order for Java to find the files Greet.class and Greet$1.class. Note also that with our custom interepreter, there's no more need for all those "standalone" options like --noinit, --noinform etc. Wrapping this in a shell script is left as an exercise, although not a difficult one.

Still, we're not quite standalone yet. For example, it's not cool to have these two Greet class files floating around like this. All other class files are in the ABCL JAR file, so we can think of adding ours in too. If we want to do that, we also need to state that the main class in the JAR file should be our Greet class, not ABCL's Main one. This can be done by modifying the so-called JAR manifest.

Let's create a manifest file first and call it Greet.txt:

Main-Class: Greet

It says what it says: our application's Main class (where the main function is) is Greet. Now let's make a copy of abcl.jar and add our class file to it:

$ cp /path/to/abcl/abcl.jar greet.jar
$ jar umf Greet.txt greet.jar Greet.class Greet$1.class
Jan 22, 2011 5:50:32 PM java.util.jar.Attributes read
WARNING: Duplicate name in Manifest: Main-Class.
Ensure that the manifest does not have duplicate entries, and
that blank lines separate individual sections in both your
manifest and in the META-INF/MANIFEST.MF entry in the jar file.

The u stands for "update", the m stands for "manifest" and the f stands for target (JAR) "file". The manifest and JAR files must appear in the same order as their corresponding options. Don't worry about the warning. That's because we're changing the Main class (ABCL had one already).

Let's try it out:

$ java -jar  greet.jar John Doe
Hello, John Doe!

Cool. But what about the Lisp file? It's still floating around. As a matter of fact, the JAR file may contain anything you want, not just class files. ABCL itself has a bunch of lisp files in its JAR file already. So we can put it in there just as well:

$ jar uf greet.jar greet.lisp

The last question is: how to have ABCL load a lisp file that's in its own JAR? The answer is: dig into the code and figure out that there is a method called Load.loadSystemFile which does just that. ABCL uses it to load its own boot.lisp for instance. We hence need to modify our main function and replace the line that calls Load.load with this one:

Load.loadSystemFile ("/greet.lisp", false, false, false);

Note the leading slash. It is needed because we have stored greet.lisp at the root of the JAR file. Let's update our JAR file once again:

$ javac -cp /path/to/abcl/abcl.jar Greet.java
$ jar uf greet.jar Greet.class Greet$1.class

And voilà! What you get this time is your application completely packed up in the JAR file. You can move this file around, distribute it... everything's inside.

Here's a final additional trick and I think we're done. As you know, ABCL stores the command-line argument list in extensions:*command-line-argument-list*. One potential problem is that there's no notion of a program name (argv[0]) in ABCL (the program is in fact always Java). Since we're going standalone, however, maybe we would like to have that. Something like, say, a variable named extensions:*argv0*. So here's a way to do it (Clon does this as part of its built-in dump facility): in the Greet class, replace the line

Interpreter.createInstance ();

with this:

Interpreter interpreter = Interpreter.createInstance ();
interpreter.eval ("(defvar extensions::*argv0* \"greet\")");
interpreter.eval ("(export 'extensions::*argv0* 'extensions)");

So that's it I guess. It seems to me that this is as far as you can go in the direction of standalone ABCL executables. Of course, this example is overly simple. We didn't try to incorporate full ASDF systems in the archive, and stuff. But you get the idea... I've attached my custom interpreter class below if you want to play with it.

Have fun!

Tuesday, December 14 2010

ELS 2011 invited speakers

I'm pleased to announce that the 4th European Lisp Symposium will feature Marc Battyani (Nova Sparks) and Craig Zilles (University of Illinois).

Monday, December 6 2010

ACCU 2011

I'm please to announce that I will be giving a talk at the next ACCU conference. The abstract is given below:

Meta-circularity... and vice-versa

As complexity increases, one often feels limited by the use of a single language, and incorporates new technology in order to express the original problem more abstractly, more precisely, and design solutions more efficiently. Using better-suited languages also has the advantage of letting you think about your problem in new and different ways, perhaps ways that you had not thought of before. It is thus no surprise to see the profusion of new languages that we face today, notably scripting and domain-specific ones.

But then, why the need for all this new and different technology? Wouldn't it be better if your primary language could evolve the way you want it to? And why is it not generally possible? Perhaps, because your primary language is not really extensible...

Meta-linguistic abstraction, that is, the art of language design plays a capital role in computer science because we have the ability to actually implement the languages we design, for instance by creating interperters for them. A fundamental idea in this context is that an interpreter is just another program (by extension, one could argue that any program is an interpreter for a particular language).

In this session, we will revive a historical moment in computer science: the birth of meta-circularity. When, in 1958, John McCarthy invented Lisp, he hadn't foreseen that given the core 7 operators of the language, it was possible to write Lisp in itself, by way of an interpreter. The practical implication of meta-circularity is that a meta-circular language gives you direct control over the semantics of the language itself, and as a consequence, means to modify or extend it. No wonder, then, why lispers never felt the need for external DSLs, scripting languages, XML or whatever. The reason is that Lisp, being extensible, can do all that by itself. Lisp is, by essence, the "programmable programming language".

Tuesday, November 30 2010

Clon v1.0b16 now supports CLISP

Hello,

I'm happy to annouce the release of Clon version 1.0 beta 16.
Most notable news for this release is the support for CLISP, which comes at the expense on one dependency (over cffi).

Grab it here.

- page 4 of 6 -

French Flag English Flag
Copyright (C) 2008 -- 2018 Didier Verna didier@lrde.epita.fr