Friday, May 15, 2009

cl-cairo2 *context* wart fixed

I pushed an updated version of cl-cairo2 to the repository today. The most important change is the fixing of a major design wart that was the result of a bad initial design choice. Originally, cl-cairo2 functions had an optional context argument as the last argument, which defaulted to *context*. This seemed to make sense at the time, it saved typing, but later on I realized it is very unLispy. So now context is the first argument, and is never optional, *context* is gone. I realize that this might break some code for people who are using cl-cairo2, and for this I apologize. But it had to be done sooner or later, I kept putting it off but finally could not bear it any more. Since I was using macros to generate most of the function definitions, effecting the change was a matter of minutes. I also cleaned up the documentation a bit.


  1. hrm, how is a special variable, especially a contextual one, unlispy?

    what i find unlispy (if there's such a thing at all) is any form of repetition.

    if *context* is the same identity through multiple invocations of various cl-cairo functions, then passing it as a mandatory first argument is repetition.

    but as i have no idea about cl-cairo, i'd better stop ranting... :)

  2. Yeah, that didn't seem unlispy at all, whatever that means.

  3. Ok, so maybe it is not "unlispy", with Lisp being so tolerant of many programming styles. I still felt it was a wart, as recently I have been drawing on many contexts simultaneously.

    I do not resent special variables as such, for example the printing functions of CL have stream bound to the standard output. But there it makes more sense because there is usually one "standard" output.

    Another thing that I found annoying with &optional (context *context*) is that when I started writing some more complex functions with keyword parameters, sometimes *context* was a keyword parameter, sometimes optional.

    Apologies if this has inconvenienced anyone. Maybe I should have done a poll instead, but I don't have an idea of how many people are using cl-cairo2.

  4. It would have been better then to make it a consistent kwarg.

    Personally I find it highly annoying to always have to specify a context parameter in front of other args.

    It also messes with the natural language meaning of ops (especially binary ops).


    move X Y => move X to Y
    move C X Y => ???


    move X Y (C) => move X to Y (in context C, specifically)

    I'm not using cl-cairo2 at the moment but it would be great if you'd reconsider. :)

  5. i think i would consistently use a keyword arg for this that defaults to the special var...

  6. Leslie: I can't say I agree about the semantics. There are no binary ops in cl-cairo2, only "commands" (functions which are mostly called for their side effects) and a few query functions.

    I would compare it to format, which also has the target stream as its second argument, even though it is "usually" t or nil. Similarly, for me it provides a nice visual regularity that context is always the first argument. I have now revised my opinion about the original solution being unlispy (thanks to Attila and Luís), but the new one still looks better to me.

    Also, having context in the first place maps the underlying syntax of the cairo library better. I do not think that bindings should blindly follow the syntax of a library when they can improve on it, but I still think it is a minor plus.

    Overall, I guess this is an issue of subjective/personal preference, and I don't claim that the new syntax is "better", I just like it better.

    Rest assured that I am not planning any major changes in cl-cairo2 in the future, I now consider the interface stable. And again, sorry for the inconvenience for people who had written lots of code using the old interface. Actually, I don't even know who is using cl-cairo2, so one of these days I should do a poll :-)

    PS.: check out cl-2d.

  7. Hi,

    just adding my $0.02

    Tamas: I understand your reasons, but i do not agree with you on the followings:

    - that having a project where you were drawing on many contexts simultaneously, encourages : 1) making *context* a requirement in the calling of drawing function. 2) optimizing library interface for that kind of projects.

    I may suggest another route using dynamic scoping to cope with later issue. and removing it from the argument list all together.

    - 'the printing functions' analogy.
    Since also there is usually one context (on average between library users).

    - and the 'format' example.
    I didn't see code or example (provide me with one, please) that stack up multiple format calls (5 and more), since usually format is used once in a while (not talking about macro generated ones), and thus no repetition. to the contrary, the graphics command usually stack up alot to do useful work.

    Still it's your library and your decision.

    thanks for your effort. and happy hacking.