discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

feedback: let, echo and assert in expressions

M
MichaelAtOz
Fri, Nov 18, 2016 3:21 AM

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something stupid...

Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it! http://www.ourfairdeal.org/  time is running out!

View this message in context: http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19205.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

doug.moen wrote > 1 a = 0; > 2 module m() > 3 { > 4 function f() = a; > 5 x = f(); > 6 a = 1; > 7 y = f(); > 8 echo(x,y); > 9 } > 10 m(); > > So the output is: > ECHO: 0,1 > > Fun question: is any of this behaviour a bug? That makes perfect sense, if you want it the other way you do > a = 0; > module m() > { > a = 1; > function f() = a; > x = f(); > y = f(); > echo(x,y); > } > m(); ----- Admin - PM me if you need anything, or if I've done something stupid... Unless specifically shown otherwise above, my contribution is in the Public Domain; to the extent possible under law, I have waived all copyright and related or neighbouring rights to this work. Obviously inclusion of works of previous authors is not included in the above. The TPP is no simple “trade agreement.” Fight it! http://www.ourfairdeal.org/ time is running out! -- View this message in context: http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19205.html Sent from the OpenSCAD mailing list archive at Nabble.com.
O
otto
Fri, Nov 18, 2016 6:12 AM

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

 function f()=a;  should persistently point to outer value.  The
 fact that function f()=a; created a local variable named with 
 token_id "a" is an artifact.

 In my opinion
 a = 1;
 a = 2;  //should at least produce a warning if not an error.

 Whereas:

 a=1;
 module m()
 {
   a=2;
 }  

  should be legal and provides for a different value of a in the
  two different scopes as it does now.

  a = 1;
  function f() = a;

  Sets the value of "a" as a local variable.  The function then
  always points to the local variable. We should provide a warning if it
  is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19205.html
Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

> doug.moen wrote > > 1 a = 0; > > 2 module m() > > 3 { > > 4 function f() = a; > > 5 x = f(); > > 6 a = 1; > > 7 y = f(); > > 8 echo(x,y); > > 9 } > > 10 m(); > > > > So the output is: > > ECHO: 0,1 > > > > Fun question: is any of this behaviour a bug? I think it is. Heres why. function f() = a; //refers to the outer scope value of a. x = f(); //sets local x to the outer scope value of a. a=1; //This should have no effect on the outer scope. function f()=a; should persistently point to outer value. The fact that function f()=a; created a local variable named with token_id "a" is an artifact. In my opinion a = 1; a = 2; //should at least produce a warning if not an error. Whereas: a=1; module m() { a=2; } should be legal and provides for a different value of a in the two different scopes as it does now. a = 1; function f() = a; Sets the value of "a" as a local variable. The function then always points to the local variable. We should provide a warning if it is redefined. Of course, since this is the behavior and it works, it isn't really a bug, it is an artifact. But it falls into the category of a gotchya, I can think of no case where there isn't a clearer method of writing this code. Everywhere this artifact is used, it tends to obfuscate. Regards Otto > > That makes perfect sense, if you want it the other way you do > > > > a = 0; > > module m() > > { > > a = 1; > > function f() = a; > > x = f(); > > y = f(); > > echo(x,y); > > } > > m(); > > > > > > ----- > Admin - PM me if you need anything, or if I've done something > stupid... > > Unless specifically shown otherwise above, my contribution is in the > Public Domain; to the extent possible under law, I have waived all > copyright and related or neighbouring rights to this work. Obviously > inclusion of works of previous authors is not included in the above. > > The TPP is no simple “trade agreement.” Fight it! > http://www.ourfairdeal.org/ time is running out! -- > View this message in context: > http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19205.html > Sent from the OpenSCAD mailing list archive at Nabble.com. > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
NH
nop head
Fri, Nov 18, 2016 10:38 AM

If you replace the calls of f() with a then you get the same result and it
makes sense since the first a refers to the outer scope and the second one
to the inner scope. So the function behaves more like a macro text
substitution. But if you move the definition of f outside the module it
always accesses the outer a.

So yes it is a strange mixture of lexical and dynamic. I thought scope was
supposed to be lexical apart from the $ variables?

On 18 November 2016 at 06:12, otto otto@123phase.com wrote:

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

  function f()=a;  should persistently point to outer value.  The
  fact that function f()=a; created a local variable named with
  token_id "a" is an artifact.

  In my opinion
  a = 1;
  a = 2;  //should at least produce a warning if not an error.

  Whereas:

  a=1;
  module m()
  {
    a=2;
  }

   should be legal and provides for a different value of a in the
   two different scopes as it does now.

   a = 1;
   function f() = a;

   Sets the value of "a" as a local variable.  The function then
   always points to the local variable. We should provide a warning if

it
is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-

in-expressions-tp19111p19205.html

Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

If you replace the calls of f() with a then you get the same result and it makes sense since the first a refers to the outer scope and the second one to the inner scope. So the function behaves more like a macro text substitution. But if you move the definition of f outside the module it always accesses the outer a. So yes it is a strange mixture of lexical and dynamic. I thought scope was supposed to be lexical apart from the $ variables? On 18 November 2016 at 06:12, otto <otto@123phase.com> wrote: > > > > > doug.moen wrote > > > 1 a = 0; > > > 2 module m() > > > 3 { > > > 4 function f() = a; > > > 5 x = f(); > > > 6 a = 1; > > > 7 y = f(); > > > 8 echo(x,y); > > > 9 } > > > 10 m(); > > > > > > So the output is: > > > ECHO: 0,1 > > > > > > Fun question: is any of this behaviour a bug? > > I think it is. Heres why. > function f() = a; //refers to the outer scope value of a. > x = f(); //sets local x to the outer scope value of a. > a=1; //This should have no effect on the outer scope. > > function f()=a; should persistently point to outer value. The > fact that function f()=a; created a local variable named with > token_id "a" is an artifact. > > In my opinion > a = 1; > a = 2; //should at least produce a warning if not an error. > > Whereas: > > a=1; > module m() > { > a=2; > } > > should be legal and provides for a different value of a in the > two different scopes as it does now. > > a = 1; > function f() = a; > > Sets the value of "a" as a local variable. The function then > always points to the local variable. We should provide a warning if > it > is redefined. > > Of course, since this is the behavior and it works, it isn't really a > bug, it is an artifact. But it falls into the category of a gotchya, > I can think of no case where there isn't a clearer method of writing > this code. Everywhere this artifact is used, it tends to obfuscate. > > Regards > Otto > > > > > That makes perfect sense, if you want it the other way you do > > > > > > > a = 0; > > > module m() > > > { > > > a = 1; > > > function f() = a; > > > x = f(); > > > y = f(); > > > echo(x,y); > > > } > > > m(); > > > > > > > > > > > > ----- > > Admin - PM me if you need anything, or if I've done something > > stupid... > > > > Unless specifically shown otherwise above, my contribution is in the > > Public Domain; to the extent possible under law, I have waived all > > copyright and related or neighbouring rights to this work. Obviously > > inclusion of works of previous authors is not included in the above. > > > > The TPP is no simple “trade agreement.” Fight it! > > http://www.ourfairdeal.org/ time is running out! -- > > View this message in context: > > http://forum.openscad.org/feedback-let-echo-and-assert- > in-expressions-tp19111p19205.html > > Sent from the OpenSCAD mailing list archive at Nabble.com. > > > > _______________________________________________ > > OpenSCAD mailing list > > Discuss@lists.openscad.org > > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >
DM
doug moen
Fri, Nov 18, 2016 1:51 PM

nop head said: I thought scope was supposed to be lexical apart from the $
variables?

That's what I thought too, for years. I think it's intended to be
lexically scoped, but the code doesn't actually work that way.

If you were to try and write a compiler for OpenSCAD, one that generates
efficient code, then you'd have to know what the lexical scoping rules
actually are, and implement those rules. It has been frustrating for me to
come up with a clear statement of what the scoping rules are, so that I
could try to implement them in my compiler.

For now, I've given up on reverse engineering the scoping rules, because I
want to work on my VM and geometry engine. Instead, I just implemented the
simplest lexical scoping rule that I could, which is that at the top level
of a script, there is only 1 namespace, and the scope of every variable and
function definition is the entire file (recursive scoping). It's simple and
consistent: it allows recursive definitions, and all you need to know as a
user is that the order of definitions doesn't matter. Plus, it is well
known how to implement this. If I consistently used "sequential scoping"
for everything, then recursive function definitions would be impossible.
The actual scoping rules for OpenSCAD are apparently very complicated, and
I don't know how to implement them using conventional compiler technology.

I think it would be beneficial if OpenSCAD were changed so that it actually
is lexically scoped, except for $ variables. And I'd like to see the
OpenSCAD team document the lexical scoping rules. In particular, what is
the scope of a variable definition? Then maybe at a later date I could
revisit this and try to write a compiler that obeys these rules.

Well defined lexical scoping rules are important for implementing first
class function values. An anonymous function literal "captures" the values
of nonlocal lexically scoped variables from surrounding scopes, at the time
the function literal is evaluated. This results in a data structure called
a closure. When the function value is subsequently called, it uses the
captured values. Function definitions work exactly the same way: nonlocal
variables are captured when the function definition is evaluated. The
variables that are captured are the ones visible at the point where the
function is defined, not at the point where the function is called.

On 18 November 2016 at 05:38, nop head nop.head@gmail.com wrote:

If you replace the calls of f() with a then you get the same result and it
makes sense since the first a refers to the outer scope and the second one
to the inner scope. So the function behaves more like a macro text
substitution. But if you move the definition of f outside the module it
always accesses the outer a.

So yes it is a strange mixture of lexical and dynamic. I thought scope was
supposed to be lexical apart from the $ variables?

On 18 November 2016 at 06:12, otto otto@123phase.com wrote:

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

  function f()=a;  should persistently point to outer value.  The
  fact that function f()=a; created a local variable named with
  token_id "a" is an artifact.

  In my opinion
  a = 1;
  a = 2;  //should at least produce a warning if not an error.

  Whereas:

  a=1;
  module m()
  {
    a=2;
  }

   should be legal and provides for a different value of a in the
   two different scopes as it does now.

   a = 1;
   function f() = a;

   Sets the value of "a" as a local variable.  The function then
   always points to the local variable. We should provide a warning if

it
is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-in-

expressions-tp19111p19205.html

Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

nop head said: I thought scope was supposed to be lexical apart from the $ variables? That's what I thought too, for years. I think it's *intended* to be lexically scoped, but the code doesn't actually work that way. If you were to try and write a compiler for OpenSCAD, one that generates efficient code, then you'd have to know what the lexical scoping rules actually are, and implement those rules. It has been frustrating for me to come up with a clear statement of what the scoping rules are, so that I could try to implement them in my compiler. For now, I've given up on reverse engineering the scoping rules, because I want to work on my VM and geometry engine. Instead, I just implemented the simplest lexical scoping rule that I could, which is that at the top level of a script, there is only 1 namespace, and the scope of every variable and function definition is the entire file (recursive scoping). It's simple and consistent: it allows recursive definitions, and all you need to know as a user is that the order of definitions doesn't matter. Plus, it is well known how to implement this. If I consistently used "sequential scoping" for everything, then recursive function definitions would be impossible. The actual scoping rules for OpenSCAD are apparently very complicated, and I don't know how to implement them using conventional compiler technology. I think it would be beneficial if OpenSCAD were changed so that it actually is lexically scoped, except for $ variables. And I'd like to see the OpenSCAD team document the lexical scoping rules. In particular, what is the scope of a variable definition? Then maybe at a later date I could revisit this and try to write a compiler that obeys these rules. Well defined lexical scoping rules are important for implementing first class function values. An anonymous function literal "captures" the values of nonlocal lexically scoped variables from surrounding scopes, at the time the function literal is evaluated. This results in a data structure called a closure. When the function value is subsequently called, it uses the captured values. Function definitions work exactly the same way: nonlocal variables are captured when the function definition is evaluated. The variables that are captured are the ones visible at the point where the function is defined, not at the point where the function is called. On 18 November 2016 at 05:38, nop head <nop.head@gmail.com> wrote: > If you replace the calls of f() with a then you get the same result and it > makes sense since the first a refers to the outer scope and the second one > to the inner scope. So the function behaves more like a macro text > substitution. But if you move the definition of f outside the module it > always accesses the outer a. > > So yes it is a strange mixture of lexical and dynamic. I thought scope was > supposed to be lexical apart from the $ variables? > > On 18 November 2016 at 06:12, otto <otto@123phase.com> wrote: > >> >> >> >> > doug.moen wrote >> > > 1 a = 0; >> > > 2 module m() >> > > 3 { >> > > 4 function f() = a; >> > > 5 x = f(); >> > > 6 a = 1; >> > > 7 y = f(); >> > > 8 echo(x,y); >> > > 9 } >> > > 10 m(); >> > > >> > > So the output is: >> > > ECHO: 0,1 >> > > >> > > Fun question: is any of this behaviour a bug? >> >> I think it is. Heres why. >> function f() = a; //refers to the outer scope value of a. >> x = f(); //sets local x to the outer scope value of a. >> a=1; //This should have no effect on the outer scope. >> >> function f()=a; should persistently point to outer value. The >> fact that function f()=a; created a local variable named with >> token_id "a" is an artifact. >> >> In my opinion >> a = 1; >> a = 2; //should at least produce a warning if not an error. >> >> Whereas: >> >> a=1; >> module m() >> { >> a=2; >> } >> >> should be legal and provides for a different value of a in the >> two different scopes as it does now. >> >> a = 1; >> function f() = a; >> >> Sets the value of "a" as a local variable. The function then >> always points to the local variable. We should provide a warning if >> it >> is redefined. >> >> Of course, since this is the behavior and it works, it isn't really a >> bug, it is an artifact. But it falls into the category of a gotchya, >> I can think of no case where there isn't a clearer method of writing >> this code. Everywhere this artifact is used, it tends to obfuscate. >> >> Regards >> Otto >> >> > >> > That makes perfect sense, if you want it the other way you do >> > >> > >> > > a = 0; >> > > module m() >> > > { >> > > a = 1; >> > > function f() = a; >> > > x = f(); >> > > y = f(); >> > > echo(x,y); >> > > } >> > > m(); >> > >> > >> > >> > >> > >> > ----- >> > Admin - PM me if you need anything, or if I've done something >> > stupid... >> > >> > Unless specifically shown otherwise above, my contribution is in the >> > Public Domain; to the extent possible under law, I have waived all >> > copyright and related or neighbouring rights to this work. Obviously >> > inclusion of works of previous authors is not included in the above. >> > >> > The TPP is no simple “trade agreement.” Fight it! >> > http://www.ourfairdeal.org/ time is running out! -- >> > View this message in context: >> > http://forum.openscad.org/feedback-let-echo-and-assert-in- >> expressions-tp19111p19205.html >> > Sent from the OpenSCAD mailing list archive at Nabble.com. >> > >> > _______________________________________________ >> > OpenSCAD mailing list >> > Discuss@lists.openscad.org >> > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> > > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
NH
nop head
Fri, Nov 18, 2016 2:03 PM

So is it just a bug in the implementation of nested functions (and
presumably nested modules) or are there other exceptions to lexical scope?

I would be surprised if much or any code relies on this so it could be bug
fixed.

On 18 November 2016 at 13:51, doug moen doug@moens.org wrote:

nop head said: I thought scope was supposed to be lexical apart from the $
variables?

That's what I thought too, for years. I think it's intended to be
lexically scoped, but the code doesn't actually work that way.

If you were to try and write a compiler for OpenSCAD, one that generates
efficient code, then you'd have to know what the lexical scoping rules
actually are, and implement those rules. It has been frustrating for me to
come up with a clear statement of what the scoping rules are, so that I
could try to implement them in my compiler.

For now, I've given up on reverse engineering the scoping rules, because I
want to work on my VM and geometry engine. Instead, I just implemented the
simplest lexical scoping rule that I could, which is that at the top level
of a script, there is only 1 namespace, and the scope of every variable and
function definition is the entire file (recursive scoping). It's simple and
consistent: it allows recursive definitions, and all you need to know as a
user is that the order of definitions doesn't matter. Plus, it is well
known how to implement this. If I consistently used "sequential scoping"
for everything, then recursive function definitions would be impossible.
The actual scoping rules for OpenSCAD are apparently very complicated, and
I don't know how to implement them using conventional compiler technology.

I think it would be beneficial if OpenSCAD were changed so that it
actually is lexically scoped, except for $ variables. And I'd like to see
the OpenSCAD team document the lexical scoping rules. In particular, what
is the scope of a variable definition? Then maybe at a later date I could
revisit this and try to write a compiler that obeys these rules.

Well defined lexical scoping rules are important for implementing first
class function values. An anonymous function literal "captures" the values
of nonlocal lexically scoped variables from surrounding scopes, at the time
the function literal is evaluated. This results in a data structure called
a closure. When the function value is subsequently called, it uses the
captured values. Function definitions work exactly the same way: nonlocal
variables are captured when the function definition is evaluated. The
variables that are captured are the ones visible at the point where the
function is defined, not at the point where the function is called.

On 18 November 2016 at 05:38, nop head nop.head@gmail.com wrote:

If you replace the calls of f() with a then you get the same result and
it makes sense since the first a refers to the outer scope and the second
one to the inner scope. So the function behaves more like a macro text
substitution. But if you move the definition of f outside the module it
always accesses the outer a.

So yes it is a strange mixture of lexical and dynamic. I thought scope
was supposed to be lexical apart from the $ variables?

On 18 November 2016 at 06:12, otto otto@123phase.com wrote:

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

  function f()=a;  should persistently point to outer value.  The
  fact that function f()=a; created a local variable named with
  token_id "a" is an artifact.

  In my opinion
  a = 1;
  a = 2;  //should at least produce a warning if not an error.

  Whereas:

  a=1;
  module m()
  {
    a=2;
  }

   should be legal and provides for a different value of a in the
   two different scopes as it does now.

   a = 1;
   function f() = a;

   Sets the value of "a" as a local variable.  The function then
   always points to the local variable. We should provide a warning

if it
is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-in-ex

pressions-tp19111p19205.html

Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

So is it just a bug in the implementation of nested functions (and presumably nested modules) or are there other exceptions to lexical scope? I would be surprised if much or any code relies on this so it could be bug fixed. On 18 November 2016 at 13:51, doug moen <doug@moens.org> wrote: > nop head said: I thought scope was supposed to be lexical apart from the $ > variables? > > That's what I thought too, for years. I think it's *intended* to be > lexically scoped, but the code doesn't actually work that way. > > If you were to try and write a compiler for OpenSCAD, one that generates > efficient code, then you'd have to know what the lexical scoping rules > actually are, and implement those rules. It has been frustrating for me to > come up with a clear statement of what the scoping rules are, so that I > could try to implement them in my compiler. > > For now, I've given up on reverse engineering the scoping rules, because I > want to work on my VM and geometry engine. Instead, I just implemented the > simplest lexical scoping rule that I could, which is that at the top level > of a script, there is only 1 namespace, and the scope of every variable and > function definition is the entire file (recursive scoping). It's simple and > consistent: it allows recursive definitions, and all you need to know as a > user is that the order of definitions doesn't matter. Plus, it is well > known how to implement this. If I consistently used "sequential scoping" > for everything, then recursive function definitions would be impossible. > The actual scoping rules for OpenSCAD are apparently very complicated, and > I don't know how to implement them using conventional compiler technology. > > I think it would be beneficial if OpenSCAD were changed so that it > actually is lexically scoped, except for $ variables. And I'd like to see > the OpenSCAD team document the lexical scoping rules. In particular, what > is the scope of a variable definition? Then maybe at a later date I could > revisit this and try to write a compiler that obeys these rules. > > Well defined lexical scoping rules are important for implementing first > class function values. An anonymous function literal "captures" the values > of nonlocal lexically scoped variables from surrounding scopes, at the time > the function literal is evaluated. This results in a data structure called > a closure. When the function value is subsequently called, it uses the > captured values. Function definitions work exactly the same way: nonlocal > variables are captured when the function definition is evaluated. The > variables that are captured are the ones visible at the point where the > function is defined, not at the point where the function is called. > > On 18 November 2016 at 05:38, nop head <nop.head@gmail.com> wrote: > >> If you replace the calls of f() with a then you get the same result and >> it makes sense since the first a refers to the outer scope and the second >> one to the inner scope. So the function behaves more like a macro text >> substitution. But if you move the definition of f outside the module it >> always accesses the outer a. >> >> So yes it is a strange mixture of lexical and dynamic. I thought scope >> was supposed to be lexical apart from the $ variables? >> >> On 18 November 2016 at 06:12, otto <otto@123phase.com> wrote: >> >>> >>> >>> >>> > doug.moen wrote >>> > > 1 a = 0; >>> > > 2 module m() >>> > > 3 { >>> > > 4 function f() = a; >>> > > 5 x = f(); >>> > > 6 a = 1; >>> > > 7 y = f(); >>> > > 8 echo(x,y); >>> > > 9 } >>> > > 10 m(); >>> > > >>> > > So the output is: >>> > > ECHO: 0,1 >>> > > >>> > > Fun question: is any of this behaviour a bug? >>> >>> I think it is. Heres why. >>> function f() = a; //refers to the outer scope value of a. >>> x = f(); //sets local x to the outer scope value of a. >>> a=1; //This should have no effect on the outer scope. >>> >>> function f()=a; should persistently point to outer value. The >>> fact that function f()=a; created a local variable named with >>> token_id "a" is an artifact. >>> >>> In my opinion >>> a = 1; >>> a = 2; //should at least produce a warning if not an error. >>> >>> Whereas: >>> >>> a=1; >>> module m() >>> { >>> a=2; >>> } >>> >>> should be legal and provides for a different value of a in the >>> two different scopes as it does now. >>> >>> a = 1; >>> function f() = a; >>> >>> Sets the value of "a" as a local variable. The function then >>> always points to the local variable. We should provide a warning >>> if it >>> is redefined. >>> >>> Of course, since this is the behavior and it works, it isn't really a >>> bug, it is an artifact. But it falls into the category of a gotchya, >>> I can think of no case where there isn't a clearer method of writing >>> this code. Everywhere this artifact is used, it tends to obfuscate. >>> >>> Regards >>> Otto >>> >>> > >>> > That makes perfect sense, if you want it the other way you do >>> > >>> > >>> > > a = 0; >>> > > module m() >>> > > { >>> > > a = 1; >>> > > function f() = a; >>> > > x = f(); >>> > > y = f(); >>> > > echo(x,y); >>> > > } >>> > > m(); >>> > >>> > >>> > >>> > >>> > >>> > ----- >>> > Admin - PM me if you need anything, or if I've done something >>> > stupid... >>> > >>> > Unless specifically shown otherwise above, my contribution is in the >>> > Public Domain; to the extent possible under law, I have waived all >>> > copyright and related or neighbouring rights to this work. Obviously >>> > inclusion of works of previous authors is not included in the above. >>> > >>> > The TPP is no simple “trade agreement.” Fight it! >>> > http://www.ourfairdeal.org/ time is running out! -- >>> > View this message in context: >>> > http://forum.openscad.org/feedback-let-echo-and-assert-in-ex >>> pressions-tp19111p19205.html >>> > Sent from the OpenSCAD mailing list archive at Nabble.com. >>> > >>> > _______________________________________________ >>> > OpenSCAD mailing list >>> > Discuss@lists.openscad.org >>> > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >> >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
NH
nop head
Fri, Nov 18, 2016 2:11 PM

I just remembered the truly bizarre rule where putting a variable
assignment in a module call that is not named in the module definition can
override the same name in another module. E.g.

b = 2;
module x(a) echo(a,b);

x(1);
x(1, b = 3);

ECHO: 1, 2

ECHO: 1, 3

That would make compilation difficult! Although I have to say interpreted
languages are always more powerful but slower and while the geometry
evaluation dominates there isn't much advantage to compiling.

On 18 November 2016 at 14:03, nop head nop.head@gmail.com wrote:

So is it just a bug in the implementation of nested functions (and
presumably nested modules) or are there other exceptions to lexical scope?

I would be surprised if much or any code relies on this so it could be bug
fixed.

On 18 November 2016 at 13:51, doug moen doug@moens.org wrote:

nop head said: I thought scope was supposed to be lexical apart from the
$ variables?

That's what I thought too, for years. I think it's intended to be
lexically scoped, but the code doesn't actually work that way.

If you were to try and write a compiler for OpenSCAD, one that generates
efficient code, then you'd have to know what the lexical scoping rules
actually are, and implement those rules. It has been frustrating for me to
come up with a clear statement of what the scoping rules are, so that I
could try to implement them in my compiler.

For now, I've given up on reverse engineering the scoping rules, because
I want to work on my VM and geometry engine. Instead, I just implemented
the simplest lexical scoping rule that I could, which is that at the top
level of a script, there is only 1 namespace, and the scope of every
variable and function definition is the entire file (recursive scoping).
It's simple and consistent: it allows recursive definitions, and all you
need to know as a user is that the order of definitions doesn't matter.
Plus, it is well known how to implement this. If I consistently used
"sequential scoping" for everything, then recursive function definitions
would be impossible. The actual scoping rules for OpenSCAD are apparently
very complicated, and I don't know how to implement them using conventional
compiler technology.

I think it would be beneficial if OpenSCAD were changed so that it
actually is lexically scoped, except for $ variables. And I'd like to see
the OpenSCAD team document the lexical scoping rules. In particular, what
is the scope of a variable definition? Then maybe at a later date I could
revisit this and try to write a compiler that obeys these rules.

Well defined lexical scoping rules are important for implementing first
class function values. An anonymous function literal "captures" the values
of nonlocal lexically scoped variables from surrounding scopes, at the time
the function literal is evaluated. This results in a data structure called
a closure. When the function value is subsequently called, it uses the
captured values. Function definitions work exactly the same way: nonlocal
variables are captured when the function definition is evaluated. The
variables that are captured are the ones visible at the point where the
function is defined, not at the point where the function is called.

On 18 November 2016 at 05:38, nop head nop.head@gmail.com wrote:

If you replace the calls of f() with a then you get the same result and
it makes sense since the first a refers to the outer scope and the second
one to the inner scope. So the function behaves more like a macro text
substitution. But if you move the definition of f outside the module it
always accesses the outer a.

So yes it is a strange mixture of lexical and dynamic. I thought scope
was supposed to be lexical apart from the $ variables?

On 18 November 2016 at 06:12, otto otto@123phase.com wrote:

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

  function f()=a;  should persistently point to outer value.  The
  fact that function f()=a; created a local variable named with
  token_id "a" is an artifact.

  In my opinion
  a = 1;
  a = 2;  //should at least produce a warning if not an error.

  Whereas:

  a=1;
  module m()
  {
    a=2;
  }

   should be legal and provides for a different value of a in the
   two different scopes as it does now.

   a = 1;
   function f() = a;

   Sets the value of "a" as a local variable.  The function then
   always points to the local variable. We should provide a warning

if it
is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-in-ex

pressions-tp19111p19205.html

Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

I just remembered the truly bizarre rule where putting a variable assignment in a module call that is not named in the module definition can override the same name in another module. E.g. b = 2; module x(a) echo(a,b); x(1); x(1, b = 3); ECHO: 1, 2 ECHO: 1, 3 That would make compilation difficult! Although I have to say interpreted languages are always more powerful but slower and while the geometry evaluation dominates there isn't much advantage to compiling. On 18 November 2016 at 14:03, nop head <nop.head@gmail.com> wrote: > So is it just a bug in the implementation of nested functions (and > presumably nested modules) or are there other exceptions to lexical scope? > > I would be surprised if much or any code relies on this so it could be bug > fixed. > > On 18 November 2016 at 13:51, doug moen <doug@moens.org> wrote: > >> nop head said: I thought scope was supposed to be lexical apart from the >> $ variables? >> >> That's what I thought too, for years. I think it's *intended* to be >> lexically scoped, but the code doesn't actually work that way. >> >> If you were to try and write a compiler for OpenSCAD, one that generates >> efficient code, then you'd have to know what the lexical scoping rules >> actually are, and implement those rules. It has been frustrating for me to >> come up with a clear statement of what the scoping rules are, so that I >> could try to implement them in my compiler. >> >> For now, I've given up on reverse engineering the scoping rules, because >> I want to work on my VM and geometry engine. Instead, I just implemented >> the simplest lexical scoping rule that I could, which is that at the top >> level of a script, there is only 1 namespace, and the scope of every >> variable and function definition is the entire file (recursive scoping). >> It's simple and consistent: it allows recursive definitions, and all you >> need to know as a user is that the order of definitions doesn't matter. >> Plus, it is well known how to implement this. If I consistently used >> "sequential scoping" for everything, then recursive function definitions >> would be impossible. The actual scoping rules for OpenSCAD are apparently >> very complicated, and I don't know how to implement them using conventional >> compiler technology. >> >> I think it would be beneficial if OpenSCAD were changed so that it >> actually is lexically scoped, except for $ variables. And I'd like to see >> the OpenSCAD team document the lexical scoping rules. In particular, what >> is the scope of a variable definition? Then maybe at a later date I could >> revisit this and try to write a compiler that obeys these rules. >> >> Well defined lexical scoping rules are important for implementing first >> class function values. An anonymous function literal "captures" the values >> of nonlocal lexically scoped variables from surrounding scopes, at the time >> the function literal is evaluated. This results in a data structure called >> a closure. When the function value is subsequently called, it uses the >> captured values. Function definitions work exactly the same way: nonlocal >> variables are captured when the function definition is evaluated. The >> variables that are captured are the ones visible at the point where the >> function is defined, not at the point where the function is called. >> >> On 18 November 2016 at 05:38, nop head <nop.head@gmail.com> wrote: >> >>> If you replace the calls of f() with a then you get the same result and >>> it makes sense since the first a refers to the outer scope and the second >>> one to the inner scope. So the function behaves more like a macro text >>> substitution. But if you move the definition of f outside the module it >>> always accesses the outer a. >>> >>> So yes it is a strange mixture of lexical and dynamic. I thought scope >>> was supposed to be lexical apart from the $ variables? >>> >>> On 18 November 2016 at 06:12, otto <otto@123phase.com> wrote: >>> >>>> >>>> >>>> >>>> > doug.moen wrote >>>> > > 1 a = 0; >>>> > > 2 module m() >>>> > > 3 { >>>> > > 4 function f() = a; >>>> > > 5 x = f(); >>>> > > 6 a = 1; >>>> > > 7 y = f(); >>>> > > 8 echo(x,y); >>>> > > 9 } >>>> > > 10 m(); >>>> > > >>>> > > So the output is: >>>> > > ECHO: 0,1 >>>> > > >>>> > > Fun question: is any of this behaviour a bug? >>>> >>>> I think it is. Heres why. >>>> function f() = a; //refers to the outer scope value of a. >>>> x = f(); //sets local x to the outer scope value of a. >>>> a=1; //This should have no effect on the outer scope. >>>> >>>> function f()=a; should persistently point to outer value. The >>>> fact that function f()=a; created a local variable named with >>>> token_id "a" is an artifact. >>>> >>>> In my opinion >>>> a = 1; >>>> a = 2; //should at least produce a warning if not an error. >>>> >>>> Whereas: >>>> >>>> a=1; >>>> module m() >>>> { >>>> a=2; >>>> } >>>> >>>> should be legal and provides for a different value of a in the >>>> two different scopes as it does now. >>>> >>>> a = 1; >>>> function f() = a; >>>> >>>> Sets the value of "a" as a local variable. The function then >>>> always points to the local variable. We should provide a warning >>>> if it >>>> is redefined. >>>> >>>> Of course, since this is the behavior and it works, it isn't really a >>>> bug, it is an artifact. But it falls into the category of a gotchya, >>>> I can think of no case where there isn't a clearer method of writing >>>> this code. Everywhere this artifact is used, it tends to obfuscate. >>>> >>>> Regards >>>> Otto >>>> >>>> > >>>> > That makes perfect sense, if you want it the other way you do >>>> > >>>> > >>>> > > a = 0; >>>> > > module m() >>>> > > { >>>> > > a = 1; >>>> > > function f() = a; >>>> > > x = f(); >>>> > > y = f(); >>>> > > echo(x,y); >>>> > > } >>>> > > m(); >>>> > >>>> > >>>> > >>>> > >>>> > >>>> > ----- >>>> > Admin - PM me if you need anything, or if I've done something >>>> > stupid... >>>> > >>>> > Unless specifically shown otherwise above, my contribution is in the >>>> > Public Domain; to the extent possible under law, I have waived all >>>> > copyright and related or neighbouring rights to this work. Obviously >>>> > inclusion of works of previous authors is not included in the above. >>>> > >>>> > The TPP is no simple “trade agreement.” Fight it! >>>> > http://www.ourfairdeal.org/ time is running out! -- >>>> > View this message in context: >>>> > http://forum.openscad.org/feedback-let-echo-and-assert-in-ex >>>> pressions-tp19111p19205.html >>>> > Sent from the OpenSCAD mailing list archive at Nabble.com. >>>> > >>>> > _______________________________________________ >>>> > OpenSCAD mailing list >>>> > Discuss@lists.openscad.org >>>> > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>> >>>> >>>> _______________________________________________ >>>> OpenSCAD mailing list >>>> Discuss@lists.openscad.org >>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>> >>> >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >>> >> >> _______________________________________________ >> OpenSCAD mailing list >> Discuss@lists.openscad.org >> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >> >> >
DM
doug moen
Fri, Nov 18, 2016 3:15 PM

nophead said: "Although I have to say interpreted languages are always more
powerful but slower and while the geometry evaluation dominates there isn't
much advantage to compiling."

Interpreted languages can be more powerful, but it depends on the
language. OpenSCAD is not a powerful language. Javascript, which is
lexically scoped and compiled, is far more powerful, and the lack of
function values in OpenSCAD is a problem for me.

Suppose we were to extend OpenSCAD so that you can define new geometric
primitives directly in the language. I mean that user defined OpenSCAD
functions would be executed during preview and rendering. And suppose we
make that fast by compiling OpenSCAD code into parallelized GPU code. Then
we would need lexical scoping and a compiler. The functional/declarative
nature of OpenSCAD really helps with this, but the dynamic scoping gets in
the way. Anyway, I think this is worth trying, you could do some really
cool things with this kind of system.

On 18 November 2016 at 09:11, nop head nop.head@gmail.com wrote:

I just remembered the truly bizarre rule where putting a variable
assignment in a module call that is not named in the module definition can
override the same name in another module. E.g.

b = 2;
module x(a) echo(a,b);

x(1);
x(1, b = 3);

ECHO: 1, 2

ECHO: 1, 3

That would make compilation difficult! Although I have to say interpreted
languages are always more powerful but slower and while the geometry
evaluation dominates there isn't much advantage to compiling.

On 18 November 2016 at 14:03, nop head nop.head@gmail.com wrote:

So is it just a bug in the implementation of nested functions (and
presumably nested modules) or are there other exceptions to lexical scope?

I would be surprised if much or any code relies on this so it could be
bug fixed.

On 18 November 2016 at 13:51, doug moen doug@moens.org wrote:

nop head said: I thought scope was supposed to be lexical apart from the
$ variables?

That's what I thought too, for years. I think it's intended to be
lexically scoped, but the code doesn't actually work that way.

If you were to try and write a compiler for OpenSCAD, one that generates
efficient code, then you'd have to know what the lexical scoping rules
actually are, and implement those rules. It has been frustrating for me to
come up with a clear statement of what the scoping rules are, so that I
could try to implement them in my compiler.

For now, I've given up on reverse engineering the scoping rules, because
I want to work on my VM and geometry engine. Instead, I just implemented
the simplest lexical scoping rule that I could, which is that at the top
level of a script, there is only 1 namespace, and the scope of every
variable and function definition is the entire file (recursive scoping).
It's simple and consistent: it allows recursive definitions, and all you
need to know as a user is that the order of definitions doesn't matter.
Plus, it is well known how to implement this. If I consistently used
"sequential scoping" for everything, then recursive function definitions
would be impossible. The actual scoping rules for OpenSCAD are apparently
very complicated, and I don't know how to implement them using conventional
compiler technology.

I think it would be beneficial if OpenSCAD were changed so that it
actually is lexically scoped, except for $ variables. And I'd like to see
the OpenSCAD team document the lexical scoping rules. In particular, what
is the scope of a variable definition? Then maybe at a later date I could
revisit this and try to write a compiler that obeys these rules.

Well defined lexical scoping rules are important for implementing first
class function values. An anonymous function literal "captures" the values
of nonlocal lexically scoped variables from surrounding scopes, at the time
the function literal is evaluated. This results in a data structure called
a closure. When the function value is subsequently called, it uses the
captured values. Function definitions work exactly the same way: nonlocal
variables are captured when the function definition is evaluated. The
variables that are captured are the ones visible at the point where the
function is defined, not at the point where the function is called.

On 18 November 2016 at 05:38, nop head nop.head@gmail.com wrote:

If you replace the calls of f() with a then you get the same result and
it makes sense since the first a refers to the outer scope and the second
one to the inner scope. So the function behaves more like a macro text
substitution. But if you move the definition of f outside the module it
always accesses the outer a.

So yes it is a strange mixture of lexical and dynamic. I thought scope
was supposed to be lexical apart from the $ variables?

On 18 November 2016 at 06:12, otto otto@123phase.com wrote:

doug.moen wrote

1    a = 0;
2    module m()
3    {
4        function f() = a;
5        x = f();
6        a = 1;
7        y = f();
8        echo(x,y);
9    }
10  m();

So the output is:
ECHO: 0,1

Fun question: is any of this behaviour a bug?

I think it is.  Heres why.
function f() = a;  //refers to the outer scope value of a.
x = f();          //sets local x to the outer scope value of a.
a=1;              //This should have no effect on the outer scope.

  function f()=a;  should persistently point to outer value.  The
  fact that function f()=a; created a local variable named with
  token_id "a" is an artifact.

  In my opinion
  a = 1;
  a = 2;  //should at least produce a warning if not an error.

  Whereas:

  a=1;
  module m()
  {
    a=2;
  }

   should be legal and provides for a different value of a in the
   two different scopes as it does now.

   a = 1;
   function f() = a;

   Sets the value of "a" as a local variable.  The function then
   always points to the local variable. We should provide a warning

if it
is redefined.

Of course, since this is the behavior and it works, it isn't really a
bug, it is an artifact.  But it falls into the category of a gotchya,
I can think of no case where there isn't a clearer method of writing
this code.  Everywhere this artifact is used, it tends to obfuscate.

Regards
Otto

That makes perfect sense, if you want it the other way you do

 a = 0;
 module m()
 {
     a = 1;
     function f() = a;
     x = f();
     y = f();
     echo(x,y);
  }
m();

Admin - PM me if you need anything, or if I've done something
stupid...

Unless specifically shown otherwise above, my contribution is in the
Public Domain; to the extent possible under law, I have waived all
copyright and related or neighbouring rights to this work. Obviously
inclusion of works of previous authors is not included in the above.

The TPP is no simple “trade agreement.”  Fight it!
http://www.ourfairdeal.org/  time is running out! --
View this message in context:
http://forum.openscad.org/feedback-let-echo-and-assert-in-ex

pressions-tp19111p19205.html

Sent from the OpenSCAD mailing list archive at Nabble.com.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.ope

nophead said: "Although I have to say interpreted languages are always more powerful but slower and while the geometry evaluation dominates there isn't much advantage to compiling." Interpreted languages *can* be more powerful, but it depends on the language. OpenSCAD is not a powerful language. Javascript, which is lexically scoped and compiled, is far more powerful, and the lack of function values in OpenSCAD is a problem for me. Suppose we were to extend OpenSCAD so that you can define new geometric primitives directly in the language. I mean that user defined OpenSCAD functions would be executed during preview and rendering. And suppose we make that fast by compiling OpenSCAD code into parallelized GPU code. Then we would need lexical scoping and a compiler. The functional/declarative nature of OpenSCAD really helps with this, but the dynamic scoping gets in the way. Anyway, I think this is worth trying, you could do some really cool things with this kind of system. On 18 November 2016 at 09:11, nop head <nop.head@gmail.com> wrote: > I just remembered the truly bizarre rule where putting a variable > assignment in a module call that is not named in the module definition can > override the same name in another module. E.g. > > b = 2; > module x(a) echo(a,b); > > x(1); > x(1, b = 3); > > ECHO: 1, 2 > > ECHO: 1, 3 > > > > That would make compilation difficult! Although I have to say interpreted > languages are always more powerful but slower and while the geometry > evaluation dominates there isn't much advantage to compiling. > > > > On 18 November 2016 at 14:03, nop head <nop.head@gmail.com> wrote: > >> So is it just a bug in the implementation of nested functions (and >> presumably nested modules) or are there other exceptions to lexical scope? >> >> I would be surprised if much or any code relies on this so it could be >> bug fixed. >> >> On 18 November 2016 at 13:51, doug moen <doug@moens.org> wrote: >> >>> nop head said: I thought scope was supposed to be lexical apart from the >>> $ variables? >>> >>> That's what I thought too, for years. I think it's *intended* to be >>> lexically scoped, but the code doesn't actually work that way. >>> >>> If you were to try and write a compiler for OpenSCAD, one that generates >>> efficient code, then you'd have to know what the lexical scoping rules >>> actually are, and implement those rules. It has been frustrating for me to >>> come up with a clear statement of what the scoping rules are, so that I >>> could try to implement them in my compiler. >>> >>> For now, I've given up on reverse engineering the scoping rules, because >>> I want to work on my VM and geometry engine. Instead, I just implemented >>> the simplest lexical scoping rule that I could, which is that at the top >>> level of a script, there is only 1 namespace, and the scope of every >>> variable and function definition is the entire file (recursive scoping). >>> It's simple and consistent: it allows recursive definitions, and all you >>> need to know as a user is that the order of definitions doesn't matter. >>> Plus, it is well known how to implement this. If I consistently used >>> "sequential scoping" for everything, then recursive function definitions >>> would be impossible. The actual scoping rules for OpenSCAD are apparently >>> very complicated, and I don't know how to implement them using conventional >>> compiler technology. >>> >>> I think it would be beneficial if OpenSCAD were changed so that it >>> actually is lexically scoped, except for $ variables. And I'd like to see >>> the OpenSCAD team document the lexical scoping rules. In particular, what >>> is the scope of a variable definition? Then maybe at a later date I could >>> revisit this and try to write a compiler that obeys these rules. >>> >>> Well defined lexical scoping rules are important for implementing first >>> class function values. An anonymous function literal "captures" the values >>> of nonlocal lexically scoped variables from surrounding scopes, at the time >>> the function literal is evaluated. This results in a data structure called >>> a closure. When the function value is subsequently called, it uses the >>> captured values. Function definitions work exactly the same way: nonlocal >>> variables are captured when the function definition is evaluated. The >>> variables that are captured are the ones visible at the point where the >>> function is defined, not at the point where the function is called. >>> >>> On 18 November 2016 at 05:38, nop head <nop.head@gmail.com> wrote: >>> >>>> If you replace the calls of f() with a then you get the same result and >>>> it makes sense since the first a refers to the outer scope and the second >>>> one to the inner scope. So the function behaves more like a macro text >>>> substitution. But if you move the definition of f outside the module it >>>> always accesses the outer a. >>>> >>>> So yes it is a strange mixture of lexical and dynamic. I thought scope >>>> was supposed to be lexical apart from the $ variables? >>>> >>>> On 18 November 2016 at 06:12, otto <otto@123phase.com> wrote: >>>> >>>>> >>>>> >>>>> >>>>> > doug.moen wrote >>>>> > > 1 a = 0; >>>>> > > 2 module m() >>>>> > > 3 { >>>>> > > 4 function f() = a; >>>>> > > 5 x = f(); >>>>> > > 6 a = 1; >>>>> > > 7 y = f(); >>>>> > > 8 echo(x,y); >>>>> > > 9 } >>>>> > > 10 m(); >>>>> > > >>>>> > > So the output is: >>>>> > > ECHO: 0,1 >>>>> > > >>>>> > > Fun question: is any of this behaviour a bug? >>>>> >>>>> I think it is. Heres why. >>>>> function f() = a; //refers to the outer scope value of a. >>>>> x = f(); //sets local x to the outer scope value of a. >>>>> a=1; //This should have no effect on the outer scope. >>>>> >>>>> function f()=a; should persistently point to outer value. The >>>>> fact that function f()=a; created a local variable named with >>>>> token_id "a" is an artifact. >>>>> >>>>> In my opinion >>>>> a = 1; >>>>> a = 2; //should at least produce a warning if not an error. >>>>> >>>>> Whereas: >>>>> >>>>> a=1; >>>>> module m() >>>>> { >>>>> a=2; >>>>> } >>>>> >>>>> should be legal and provides for a different value of a in the >>>>> two different scopes as it does now. >>>>> >>>>> a = 1; >>>>> function f() = a; >>>>> >>>>> Sets the value of "a" as a local variable. The function then >>>>> always points to the local variable. We should provide a warning >>>>> if it >>>>> is redefined. >>>>> >>>>> Of course, since this is the behavior and it works, it isn't really a >>>>> bug, it is an artifact. But it falls into the category of a gotchya, >>>>> I can think of no case where there isn't a clearer method of writing >>>>> this code. Everywhere this artifact is used, it tends to obfuscate. >>>>> >>>>> Regards >>>>> Otto >>>>> >>>>> > >>>>> > That makes perfect sense, if you want it the other way you do >>>>> > >>>>> > >>>>> > > a = 0; >>>>> > > module m() >>>>> > > { >>>>> > > a = 1; >>>>> > > function f() = a; >>>>> > > x = f(); >>>>> > > y = f(); >>>>> > > echo(x,y); >>>>> > > } >>>>> > > m(); >>>>> > >>>>> > >>>>> > >>>>> > >>>>> > >>>>> > ----- >>>>> > Admin - PM me if you need anything, or if I've done something >>>>> > stupid... >>>>> > >>>>> > Unless specifically shown otherwise above, my contribution is in the >>>>> > Public Domain; to the extent possible under law, I have waived all >>>>> > copyright and related or neighbouring rights to this work. Obviously >>>>> > inclusion of works of previous authors is not included in the above. >>>>> > >>>>> > The TPP is no simple “trade agreement.” Fight it! >>>>> > http://www.ourfairdeal.org/ time is running out! -- >>>>> > View this message in context: >>>>> > http://forum.openscad.org/feedback-let-echo-and-assert-in-ex >>>>> pressions-tp19111p19205.html >>>>> > Sent from the OpenSCAD mailing list archive at Nabble.com. >>>>> > >>>>> > _______________________________________________ >>>>> > OpenSCAD mailing list >>>>> > Discuss@lists.openscad.org >>>>> > http://lists.openscad.org/mailman/listinfo/discuss_lists.ope >>>>> nscad.org >>>>> >>>>> >>>>> _______________________________________________ >>>>> OpenSCAD mailing list >>>>> Discuss@lists.openscad.org >>>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>>> >>>> >>>> >>>> _______________________________________________ >>>> OpenSCAD mailing list >>>> Discuss@lists.openscad.org >>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>>> >>>> >>> >>> _______________________________________________ >>> OpenSCAD mailing list >>> Discuss@lists.openscad.org >>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >>> >>> >> > > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org > >
A
adrian
Fri, Nov 18, 2016 3:16 PM

nophead wrote

I just remembered the truly bizarre rule where putting a variable
assignment in a module call that is not named in the module definition can
override the same name in another module. E.g.

b = 2;
module x(a) echo(a,b);

x(1);
x(1, b = 3);

ECHO: 1, 2

ECHO: 1, 3

I thought that was just an artifact of the $ variables that can be passed
in.  Basically, you can override any external variable by specifying a
particular value in the function arguments, making a scope bubble layer that
goes between the local and outer scope.

Thought it was odd, but interesting.

A

--
View this message in context: http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19213.html
Sent from the OpenSCAD mailing list archive at Nabble.com.

nophead wrote > I just remembered the truly bizarre rule where putting a variable > assignment in a module call that is not named in the module definition can > override the same name in another module. E.g. > > b = 2; > module x(a) echo(a,b); > > x(1); > x(1, b = 3); > > ECHO: 1, 2 > > ECHO: 1, 3 I thought that was just an artifact of the $ variables that can be passed in. Basically, you can override any external variable by specifying a particular value in the function arguments, making a scope bubble layer that goes between the local and outer scope. Thought it was odd, but interesting. A -- View this message in context: http://forum.openscad.org/feedback-let-echo-and-assert-in-expressions-tp19111p19213.html Sent from the OpenSCAD mailing list archive at Nabble.com.
MK
Marius Kintel
Fri, Nov 18, 2016 3:28 PM

On Nov 18, 2016, at 09:11, nop head nop.head@gmail.com wrote:

module x(a) echo(a,b);
x(1, b = 3);

We merge the entire argument list into the local scope of the module at call time. This was probably initially done to pass dynamically scoped variables. I would consider the fact that regular assignments slipped through a bug.

-Marius

> On Nov 18, 2016, at 09:11, nop head <nop.head@gmail.com> wrote: > > module x(a) echo(a,b); > x(1, b = 3); > We merge the entire argument list into the local scope of the module at call time. This was probably initially done to pass dynamically scoped variables. I would consider the fact that regular assignments slipped through a bug. -Marius
MK
Marius Kintel
Fri, Nov 18, 2016 3:39 PM

On Nov 18, 2016, at 08:51, doug moen doug@moens.org wrote:

I think it would be beneficial if OpenSCAD were changed so that it actually is lexically scoped, except for $ variables.

I agree. I’d like to see a way of providing very clear messages to people exploiting this behavior that it’s deprecated, ideally with a way of upgrading code to follow the new rules.

And I'd like to see the OpenSCAD team document the lexical scoping rules. In particular, what is the scope of a variable definition? Then maybe at a later date I could revisit this and try to write a compiler that obeys these rules.

I’m not sure anyone wants to document these rules as they’re mostly artifacts of poorly written/tested code in the past. Extracting docs from code is not always easy..
Most of this is implicitly available as tests. Any new compiler could reuse these test cases.
Rather than documenting it, we could always identify usage of such with tests, and write rules on the AST level to detect usage of said features, and potentially provide an upgrade path.

-Marius

> On Nov 18, 2016, at 08:51, doug moen <doug@moens.org> wrote: > > I think it would be beneficial if OpenSCAD were changed so that it actually is lexically scoped, except for $ variables. I agree. I’d like to see a way of providing very clear messages to people exploiting this behavior that it’s deprecated, ideally with a way of upgrading code to follow the new rules. > And I'd like to see the OpenSCAD team document the lexical scoping rules. In particular, what is the scope of a variable definition? Then maybe at a later date I could revisit this and try to write a compiler that obeys these rules. > I’m not sure anyone wants to document these rules as they’re mostly artifacts of poorly written/tested code in the past. Extracting docs from code is not always easy.. Most of this is implicitly available as tests. Any new compiler could reuse these test cases. Rather than documenting it, we could always identify usage of such with tests, and write rules on the AST level to detect usage of said features, and potentially provide an upgrade path. -Marius