I've played with the recent PS with lexical scoping, and it's grown on me. My concerns about the readability of gensym'd suffixes are not turning out to be as bad as I worried, and I'm noticing several benefits to the idea. I'm hoping the recent batch of bugs we've reported can be fixed so we can upgrade to the latest.
In the meantime, I'm trying to understand the intent behind this bit of language redesign. Consider the following:
(ps (let ((a 123)) (blah a)) (alert a))
If this were really lexically scoped, the a in the alert form would be undefined. But ps generates:
"var a = 123; blah(a); alert(a);"
Does this reflect what is intended? If so, is there a clear explanation of just what "lexical scoping" is now offered by PS, i.e. what the rules are, what we should expect, and what we should not expect?
Daniel
If this were really lexically scoped, the a in the alert form would be undefined. But ps generates:
"var a = 123; blah(a); alert(a);"
Does this reflect what is intended? If so, is there a clear explanation of just what "lexical scoping" is now offered by PS, i.e. what the rules are, what we should expect, and what we should not expect?
Currently PS implements lexical scoping by taking advantage of JS's lexical scoping. Since JS does not have a special form to introduce arbitrary lexical scopes (aside from "wrap everything in a lambda"), this is accomplished by "pushing up" the actual variable definition to the nearest enclosing JS lexical scope. This may either be the nearest enclosing function definition (defun or lambda), or if there is none, the JS toplevel. In the case of that example it happens to be the toplevel. That's where name collisions will probably become a problem and the mechanism breaks down. Which is not a terrible thing as it's basically doing what PS used to do before, and that worked ok.
When the code is inside a function, you get a real lexical scope when you declare a variable. The variable renaming introduced recently is an implementation technique for doing arbitrary nested lexical scopes using a single flat scope, but it depends on that scope being there.
So basically any form that introduces a lexical binding inside a defun/lambda should correspond exactly to CL semantics (if not, it's a bug!). Anything that's in the toplevel will either introduce a new top-level lexical variable, or change the value of an existing one.
I guess one thing that can be done is to wrap any let forms in the toplevel into a lambda that's called right then and there. I personally don't like the toplevel/non-toplevel dimorphism in the generated code so I'm not going to do it unless a compelling reason is found.
Vladimir
Daniel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
On Sun, Jun 7, 2009 at 11:46 PM, Vladimir Sedach vsedach@gmail.com wrote:
So basically any form that introduces a lexical binding inside a defun/lambda should correspond exactly to CL semantics (if not, it's a bug!). Anything that's in the toplevel will either introduce a new top-level lexical variable, or change the value of an existing one.
I have not tried out the lexical scoping yet, so I cannot be sure how this works. Is there a means of declaring variables special? So if you have
(defvar *g* 1)
(defun foo () (let ((*g* 5)) (declare (special *g*)) (print-g))) (print-g))
(defun print-g () (print *g*))
It will 51 and not 11 or 55? I am unsure of the current semantics of let--whether anything is treated as dynamic and rebound, etc. Is the manual up to date?
Best, Red
I guess one thing that can be done is to wrap any let forms in the toplevel into a lambda that's called right then and there. I personally don't like the toplevel/non-toplevel dimorphism in the generated code so I'm not going to do it unless a compelling reason is found.
Vladimir
Daniel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
Special variables are still there, implemented using JS globals and try-finally to rebind them. So the semantics of those should be the same as that of CL as well.
Vladimir
On Mon, Jun 8, 2009 at 2:30 AM, Red Dalyreddaly@gmail.com wrote:
On Sun, Jun 7, 2009 at 11:46 PM, Vladimir Sedach vsedach@gmail.com wrote:
So basically any form that introduces a lexical binding inside a defun/lambda should correspond exactly to CL semantics (if not, it's a bug!). Anything that's in the toplevel will either introduce a new top-level lexical variable, or change the value of an existing one.
I have not tried out the lexical scoping yet, so I cannot be sure how this works. Is there a means of declaring variables special? So if you have
(defvar *g* 1)
(defun foo () (let ((*g* 5)) (declare (special *g*)) (print-g))) (print-g))
(defun print-g () (print *g*))
It will 51 and not 11 or 55? I am unsure of the current semantics of let--whether anything is treated as dynamic and rebound, etc. Is the manual up to date?
Best, Red
I guess one thing that can be done is to wrap any let forms in the toplevel into a lambda that's called right then and there. I personally don't like the toplevel/non-toplevel dimorphism in the generated code so I'm not going to do it unless a compelling reason is found.
Vladimir
Daniel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel mailing list parenscript-devel@common-lisp.net http://common-lisp.net/cgi-bin/mailman/listinfo/parenscript-devel
parenscript-devel@common-lisp.net