[parenscript-devel] Lisp-like shadowing behavior

Daniel Gackle danielgackle at gmail.com
Thu Apr 17 22:05:37 UTC 2008


A few months ago, Vladimir posted an email along with a rather dramatic new
feature in Parenscript: the ability to dynamically rebind vars within a
scope and have their original value restored on leaving the scope; in other
words, Lisp-style special variables. As part of this change, "defvar" was
redefined to declare this new kind of variable (invoking quite different
behavior by the PS compiler under the hood). If you want old-fashioned JS
variables you now need to say "var" instead. I both like and dislike this.

What I like: the feature itself. One of the best things about Common Lisp
is that we get the advantages of global variables without the pain. I had
even written a ps macro to do something similar in a few cases. But those
cases are rare. The vast majority of the time I *don't *want this behavior;
I want plain JS variables. This is because I need runtime performance, ease
of debugging, and and so on.

I also like the idea of ordinary JS variables being declared using "var",
not "defvar". That's because "var" reminds me that I'm dealing with JS
scoping rules which are so different from Lisp's. It's also shorter.

What I dislike: the use of the term "defvar" to declare the new type of
variable.  I'm skeptical for three reasons:

1. The word "defvar" is very similar to "var", whereas the behavior of the
two is very different;
2. "defvar" has a specific meaning in the Lisp world and it's not what PS is
doing here. This is misleading. PS is not Lisp, and we shouldn't establish
nominal equivalences where there isn't a semantic equivalence (or at least a
close correspondence).
3. Lots of existing PS code says "defvar" to mean "var", all of which will
now break. Actually, it's worse. It breaks in a few strange places, while
silently compiling (but generating considerably more complex JS) most of the
time.

For these reasons I'm thinking we should keep the feature, but not use
"defvar" for it. I'd suggest either "define-special-variable" or
"defparameter". The former is verbose but explicit. The latter is more
Lispy, addresses #1 and #3 completely and does a better job on #2. I guess I
have a slight preference for "defparameter" for the somewhat embarrassing
reason that it will be syntax highlighted in Emacs.

This would then free up the term "defvar", allowing PS to apply the same
policy here that was used in previous cases of name changes: keep the
behavior the same as it was, but issue a "deprecated" warning specifying
what the new term should be.

Opinions?

Daniel



On Mon, Dec 24, 2007 at 7:25 PM, Vladimir Sedach <vsedach at gmail.com> wrote:

> Instead of introducing a new special form or macro, I decided to
> follow Common Lisp and make defvar define top-level special forms,
> which are automatically dynamically bound by let. Now you need to use
> the special form 'var' if you just want to define regular globals.
> This, and a few other minor things are now in the darcs repository
> (which should have sent a message to this group after my push, but I
> guess I didn't configure it right, yet).
>
> Merry X-mas,
> Vladimir
>
> On 11/6/07, Daniel Gackle <danielgackle at gmail.com> wrote:
> > Below is a ps macro that simulates the shadowing of special variables in
> > Lisp. I'm wondering if anyone thinks this would be useful to add to
> > Parenscript.
> >
> > I wrote it because I have some Javascript functions that reference
> global
> > variables, and wanted to write some test functions for those without
> > modifying global state. One option of course would be to simply write
> the
> > original functions to take parameters instead of the global variables.
> But
> > that complicates their signatures and I'm loath to modify production
> code to
> > suit tests. With this macro, my test can do this:
> >
> >   (ps (shadow-let ((*global-var* "test value"))
> >      (function-that-uses-global-var)))
> >
> > and the original value of *global-var* will be restored:
> >
> >   var _js3778 = null;
> >   try {
> >       _js3778 = GLOBALVAR;
> >       GLOBALVAR = 'test value';
> >       functionThatUsesGlobalVar();
> >   } finally {
> >       GLOBALVAR = _js3778;
> >   };
> >
> > Daniel
> >
> > ------------------------------------------------------------------------
> >
> > (defpsmacro shadow-let (bindings &body body)
> >   (labels ((wrap-expr (bindings body)
> >       (if (null bindings)
> >    body
> >    (list (list 'temporarily-bind (car bindings) (wrap-expr (cdr
> bindings)
> > body))))))
> >     `(macrolet ((temporarily-bind ((var expr) body)
> >     (with-ps-gensyms (temp)
> >       `(progn (defvar ,temp nil)
> >        (try (progn (setf ,temp ,var)
> >      (setf ,var ,expr)
> >      , at body)
> >      (:finally (setf ,var ,temp)))))))
> >        ,(cons 'progn (wrap-expr bindings body)))))
> > _______________________________________________
> > parenscript-devel mailing list
> > parenscript-devel at common-lisp.net
> > http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
> >
> >
> _______________________________________________
> parenscript-devel mailing list
> parenscript-devel at common-lisp.net
> http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/parenscript-devel/attachments/20080417/7579f26f/attachment.html>


More information about the parenscript-devel mailing list