"interesting" scoping behavior for $ variables

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

"interesting" scoping behavior for $ variables

JordanBrown

When playing with my "tracking" transformation modules, I discovered an ... interesting ... scoping behavior of $ variables.  It seems undesirable, but I don't immediately see how to fix it.

What "should" the output of this program be?

$x=1;

module foo() {
    $x=2;
    children();
}

foo() {
    x = $x;
    echo(x=x, $x=$x);
}

I expected:

ECHO: x = 2, $x = 2

What it outputs:

ECHO: x = 1, $x = 2

The reason is that the assignments for foo's child block are executed before any part of foo itself is executed, and then the modules for foo's children are executed when they are referenced with children(), after foo's own assignments and during its module execution.

This is a problem for my world-coordinate work, because it means that a reference to the local matrix inside the top level of a transformation's child block sees the transformation matrix *before* that transformation.  In my implementation:

translate([10,0,0]) {
    p = whereis([0,0,0]);
    echo(p);
}

yields [0,0,0] instead of [10,0,0].  Revar's implementation suffers a similar fate:

translate([30,40,50]) {
    p = local_translation();
    echo(p);
}

also yields [0,0,0].

There's a workaround:  if the assignment is not in the top level of the child block then it doesn't get done until the children are referenced:

translate([10,0,0]) union() {
    p = whereis([0,0,0]);
    echo(p);
}

but I don't immediately see a way to work around it transparently, because the parent module doesn't get any chance at all to execute before the assignments in the top level of its child block are done.

I suspect that this would be tough to change, because (a) the child-block's assignments need to be executed before any of the children are executed and preferably only once, and (b) the parent module may do $ assignments during its own module-execution phase.  Perhaps the answer is that the child-block's assignments could be done on each call to children(), but that seems painful.  (But it also seems more correct, since different invocations of children() could have different values set into $ variables.)

I haven't a clue whether a "native" implementation of the world-coordinate-transformation-tracking mechanism could avoid this by doing its work before the child-block's assignments.


_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: "interesting" scoping behavior for $ variables

Ronaldo
You will get what you want with:

foo() {
    let( x = $x) {
    echo(x=x, $x=$x);
    }
}

Em sex., 23 de out. de 2020 às 17:49, Jordan Brown <[hidden email]> escreveu:

When playing with my "tracking" transformation modules, I discovered an ... interesting ... scoping behavior of $ variables.  It seems undesirable, but I don't immediately see how to fix it.

What "should" the output of this program be?

$x=1;

module foo() {
    $x=2;
    children();
}

foo() {
    x = $x;
    echo(x=x, $x=$x);
}

I expected:

ECHO: x = 2, $x = 2

What it outputs:

ECHO: x = 1, $x = 2

The reason is that the assignments for foo's child block are executed before any part of foo itself is executed, and then the modules for foo's children are executed when they are referenced with children(), after foo's own assignments and during its module execution.

This is a problem for my world-coordinate work, because it means that a reference to the local matrix inside the top level of a transformation's child block sees the transformation matrix *before* that transformation.  In my implementation:

translate([10,0,0]) {
    p = whereis([0,0,0]);
    echo(p);
}

yields [0,0,0] instead of [10,0,0].  Revar's implementation suffers a similar fate:

translate([30,40,50]) {
    p = local_translation();
    echo(p);
}

also yields [0,0,0].

There's a workaround:  if the assignment is not in the top level of the child block then it doesn't get done until the children are referenced:

translate([10,0,0]) union() {
    p = whereis([0,0,0]);
    echo(p);
}

but I don't immediately see a way to work around it transparently, because the parent module doesn't get any chance at all to execute before the assignments in the top level of its child block are done.

I suspect that this would be tough to change, because (a) the child-block's assignments need to be executed before any of the children are executed and preferably only once, and (b) the parent module may do $ assignments during its own module-execution phase.  Perhaps the answer is that the child-block's assignments could be done on each call to children(), but that seems painful.  (But it also seems more correct, since different invocations of children() could have different values set into $ variables.)

I haven't a clue whether a "native" implementation of the world-coordinate-transformation-tracking mechanism could avoid this by doing its work before the child-block's assignments.

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Reply | Threaded
Open this post in threaded view
|

Re: "interesting" scoping behavior for $ variables

JordanBrown
On 10/23/2020 10:10 AM, Ronaldo Persiano wrote:
You will get what you want with:

foo() {
    let( x = $x) {
    echo(x=x, $x=$x);
    }
}

Yes, and also with:
foo() {
    let() {
        x = $x;
        echo(x=x, $x=$x);
    }
}

Both of those work because the assignment of x is inside a child of foo() rather than in foo()'s child-block top-level assignments.

The goal is to have this be transparent to the caller, and in particular to allow the caller to use a function that depends on the parent module's $ variable settings.



_______________________________________________
OpenSCAD mailing list
[hidden email]
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org