Bug or my misunderstanding of 'for'?

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

Bug or my misunderstanding of 'for'?

alexgibson

Hi all,

 

This produces the correct result, ‘lilypads’ at all 4 corners of an A3 sized 3D print.

 

for(i=[-0.5,0.5],j=[-0.5,0.5])

                {

                translate([297*i,420*j,0])

                                cylinder(0.2,15,15);

                }

 

However this, which I tried first, did not work, and shows only 2 corners:

 

for(i=[-0.5,0.5])

                {

                translate([297*i,420*i,0])

                                cylinder(0.2,15,15);

                }

 

Two things bug me:

1)      I’m sure I used to be able to get away with the same variable twice.

2)      I don’t see what the problem is, as it’s clearly recognised that

a.       The x translation  is moved by i * 297

b.      The y translation  is moved by i * 420

c.       One disc is moved by both +ve values, the other by both -ve values

 

Version is 2019.05, on Windows 10. 

 

Trying to answer my own question… 

is it the case that OpenSCAD  processes the contents of the braces twice: once for the first value for ‘i’, -0.5, then again for the second value, +0.5?  And does not apply the other combination of cases that are valid?

 

Is this a behaviour that was changed at some point deliberately, or did I imagine being able to get away with placing 4 corner pieces, or drilling 4 holes with just one for() variable?

 

Is there something I may have done subtly differently before to get the result I was expecting with only one variable – or do I just need to always define a second, to my mind redundant, variable?

 

Thanks for any illumination of this process!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 


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

Re: Bug or my misunderstanding of 'for'?

nophead
The for loop is iterating through a list with two elements, -0.5 and +0.5 so it will only create two objects, no matter what you do with the result. Not sure why you would think otherwise. If you use i in both the x and y expressions it has the same value for one iteration and the second value for the other.

To make four holes with one loop perhaps you rotated by 90 degrees, or indexed a table to get independent x and y values. The straight forward way is to use two variables as your first example. It has always been like that.

On Thu, 18 Jun 2020 at 16:28, Alex Gibson <[hidden email]> wrote:

Hi all,

 

This produces the correct result, ‘lilypads’ at all 4 corners of an A3 sized 3D print.

 

for(i=[-0.5,0.5],j=[-0.5,0.5])

                {

                translate([297*i,420*j,0])

                                cylinder(0.2,15,15);

                }

 

However this, which I tried first, did not work, and shows only 2 corners:

 

for(i=[-0.5,0.5])

                {

                translate([297*i,420*i,0])

                                cylinder(0.2,15,15);

                }

 

Two things bug me:

1)      I’m sure I used to be able to get away with the same variable twice.

2)      I don’t see what the problem is, as it’s clearly recognised that

a.       The x translation  is moved by i * 297

b.      The y translation  is moved by i * 420

c.       One disc is moved by both +ve values, the other by both -ve values

 

Version is 2019.05, on Windows 10. 

 

Trying to answer my own question… 

is it the case that OpenSCAD  processes the contents of the braces twice: once for the first value for ‘i’, -0.5, then again for the second value, +0.5?  And does not apply the other combination of cases that are valid?

 

Is this a behaviour that was changed at some point deliberately, or did I imagine being able to get away with placing 4 corner pieces, or drilling 4 holes with just one for() variable?

 

Is there something I may have done subtly differently before to get the result I was expecting with only one variable – or do I just need to always define a second, to my mind redundant, variable?

 

Thanks for any illumination of this process!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

_______________________________________________
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: Bug or my misunderstanding of 'for'?

alexgibson

Thanks Chris, so I’ve correctly understood what’s going on, but somehow must have a false memory of it ever working another way! 

 

It’s quite possible I might have used a rotation.  Will go back over some older code and see.

The ‘other way’ I imagined this *could* work is that for the contents of the braces, every time it gets to an instance of ‘i’, it could apply both (/all) values of ‘i’.  This results in the  grid of 4 possible outcomes.

At least I can now eliminate that from my thinking and that was the purpose of asking the question!

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

From: Discuss [mailto:[hidden email]] On Behalf Of nop head
Sent: 18 June 2020 16:48
To: OpenSCAD general discussion
Subject: Re: [OpenSCAD] Bug or my misunderstanding of 'for'?

 

The for loop is iterating through a list with two elements, -0.5 and +0.5 so it will only create two objects, no matter what you do with the result. Not sure why you would think otherwise. If you use i in both the x and y expressions it has the same value for one iteration and the second value for the other.

 

To make four holes with one loop perhaps you rotated by 90 degrees, or indexed a table to get independent x and y values. The straight forward way is to use two variables as your first example. It has always been like that.

 

On Thu, 18 Jun 2020 at 16:28, Alex Gibson <[hidden email]> wrote:

Hi all,

 

This produces the correct result, ‘lilypads’ at all 4 corners of an A3 sized 3D print.

 

for(i=[-0.5,0.5],j=[-0.5,0.5])

                {

                translate([297*i,420*j,0])

                                cylinder(0.2,15,15);

                }

 

However this, which I tried first, did not work, and shows only 2 corners:

 

for(i=[-0.5,0.5])

                {

                translate([297*i,420*i,0])

                                cylinder(0.2,15,15);

                }

 

Two things bug me:

1)      I’m sure I used to be able to get away with the same variable twice.

2)      I don’t see what the problem is, as it’s clearly recognised that

a.       The x translation  is moved by i * 297

b.      The y translation  is moved by i * 420

c.       One disc is moved by both +ve values, the other by both -ve values

 

Version is 2019.05, on Windows 10. 

 

Trying to answer my own question… 

is it the case that OpenSCAD  processes the contents of the braces twice: once for the first value for ‘i’, -0.5, then again for the second value, +0.5?  And does not apply the other combination of cases that are valid?

 

Is this a behaviour that was changed at some point deliberately, or did I imagine being able to get away with placing 4 corner pieces, or drilling 4 holes with just one for() variable?

 

Is there something I may have done subtly differently before to get the result I was expecting with only one variable – or do I just need to always define a second, to my mind redundant, variable?

 

Thanks for any illumination of this process!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

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

 

Virus-free. www.avg.com

 


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

Re: Bug or my misunderstanding of 'for'?

JordanBrown
On 6/18/2020 9:07 AM, Alex Gibson wrote:

The ‘other way’ I imagined this *could* work is that for the contents of the braces, every time it gets to an instance of ‘i’, it could apply both (/all) values of ‘i’.  This results in the  grid of 4 possible outcomes.


That would yield some very peculiar results.
for (i = [1,2]) echo(i*2, i+i);

would yield, I think:

2, 2
2, 3
2, 3
2, 4
4, 2
4, 3
4, 3
4, 4

and of course the number of combinations would explode as the number of values and the number of references increase.



  


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

Re: Bug or my misunderstanding of 'for'?

alexgibson

I see!

 

So, while it might be useful and quicker in my use case, it could cause an unacceptable lack of constraint in others!

 

At the risk of putting my ignorance of programming languages formation on full display, but in the spirit of ‘don’t repeat yourself’, is there not a shorter way to use a globally defined range of numbers in a for() loop?

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (plus_minus_halves,one_two_three)

                {

                translate([20*plus_minus_halves,40*one_two_three,0])

                cylinder(0.2,15,15);

                }

 

…results in no movement – but also no error!

 

Whereas this works, and seems to be saying the same thing…

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (i=plus_minus_halves,j=one_two_three)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

You can even write the same thing as:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=j)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Is that just a case of ‘that’s the syntax’ or is there something that is usefully being done by forcing the for() loop to define the variables in what feels to me like a redundant way?

 

This is an odd (to me) case:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=i)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Results in:

 

…whereas…

 

india = [-0.5,0.5];

juliet = [1,2,3];

 

for (i=india,j=india)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Gives you..

 

So even though in the for() variable, we first say that i (within the for loop) is i (as defined earlier), saying j=i does not result in an output matching either instance???

 

I find that a bit odd.  No doubt there is a sensible reason for this!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

From: Jordan Brown [mailto:[hidden email]]
Sent: 18 June 2020 17:35
To: OpenSCAD general discussion; Alex Gibson
Subject: Re: [OpenSCAD] Bug or my misunderstanding of 'for'?

 

On 6/18/2020 9:07 AM, Alex Gibson wrote:

The ‘other way’ I imagined this *could* work is that for the contents of the braces, every time it gets to an instance of ‘i’, it could apply both (/all) values of ‘i’.  This results in the  grid of 4 possible outcomes.


That would yield some very peculiar results.

for (i = [1,2]) echo(i*2, i+i);

would yield, I think:

2, 2
2, 3
2, 3
2, 4
4, 2
4, 3
4, 3
4, 4

and of course the number of combinations would explode as the number of values and the number of references increase.

 

 

 

Virus-free. www.avg.com

 


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

Re: Bug or my misunderstanding of 'for'?

nophead
For your first version I get an error: WARNING: Unable to convert translate([[-10, 10], [40, 80, 120], 0]) parameter to a vec3 or vec2 of numbers, in file , line 11 


I am surprised for without a variable doesn't give an error though. It executes the loop but as there is no variable each iteration is identical.


i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=i)

The j = i now refers to the variable i, not the list i.





On Thu, 18 Jun 2020 at 18:15, Alex Gibson <[hidden email]> wrote:

I see!

 

So, while it might be useful and quicker in my use case, it could cause an unacceptable lack of constraint in others!

 

At the risk of putting my ignorance of programming languages formation on full display, but in the spirit of ‘don’t repeat yourself’, is there not a shorter way to use a globally defined range of numbers in a for() loop?

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (plus_minus_halves,one_two_three)

                {

                translate([20*plus_minus_halves,40*one_two_three,0])

                cylinder(0.2,15,15);

                }

 

…results in no movement – but also no error!

 

Whereas this works, and seems to be saying the same thing…

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (i=plus_minus_halves,j=one_two_three)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

You can even write the same thing as:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=j)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Is that just a case of ‘that’s the syntax’ or is there something that is usefully being done by forcing the for() loop to define the variables in what feels to me like a redundant way?

 

This is an odd (to me) case:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=i)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Results in:

 

…whereas…

 

india = [-0.5,0.5];

juliet = [1,2,3];

 

for (i=india,j=india)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Gives you..

 

So even though in the for() variable, we first say that i (within the for loop) is i (as defined earlier), saying j=i does not result in an output matching either instance???

 

I find that a bit odd.  No doubt there is a sensible reason for this!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

From: Jordan Brown [mailto:[hidden email]]
Sent: 18 June 2020 17:35
To: OpenSCAD general discussion; Alex Gibson
Subject: Re: [OpenSCAD] Bug or my misunderstanding of 'for'?

 

On 6/18/2020 9:07 AM, Alex Gibson wrote:

The ‘other way’ I imagined this *could* work is that for the contents of the braces, every time it gets to an instance of ‘i’, it could apply both (/all) values of ‘i’.  This results in the  grid of 4 possible outcomes.


That would yield some very peculiar results.

for (i = [1,2]) echo(i*2, i+i);

would yield, I think:

2, 2
2, 3
2, 3
2, 4
4, 2
4, 3
4, 3
4, 4

and of course the number of combinations would explode as the number of values and the number of references increase.

 

 

 

Virus-free. www.avg.com

 

_______________________________________________
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: Bug or my misunderstanding of 'for'?

JordanBrown
In reply to this post by alexgibson
On 6/18/2020 10:14 AM, Alex Gibson wrote:
So, while it might be useful and quicker in my use case, it could cause an unacceptable lack of constraint in others!

More that in the general case it wouldn't be a useful interpretation.

At the risk of putting my ignorance of programming languages formation on full display, but in the spirit of ‘don’t repeat yourself’, is there not a shorter way to use a globally defined range of numbers in a for() loop?

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (plus_minus_halves,one_two_three)

                {

                translate([20*plus_minus_halves,40*one_two_three,0])

                cylinder(0.2,15,15);

                }

 

…results in no movement – but also no error!


I suspect that it's an accident that that "for" is not considered to be an error.  What it seems to do is to iterate across the vector(s) without assigning the values to any names.

In the translate, plus_minus_halves and one_two_three are still vectors.  Multiplying a vector by a number is allowed, but what you're then passing to translate is a vector consisting of a two-entry vector, a three-entry vector, and a zero.  That's not a legal input for translate().

Whereas this works, and seems to be saying the same thing…

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (i=plus_minus_halves,j=one_two_three)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

That assigns successive values from the vectors to i and j.

Considering the simpler case first:

v = [1,2,3];
for (i = v) {
    echo(i);
}

evaluates the body once for each element in v, setting i equal to that element.  That is, the body is evaluated once with i=1, once with i=2, and once with i=3.

A "for" with multiple values is treated like nested "for"s:

v1 = [1,2,3];
v2 = [4,5,6];
for (i = v1, j = v2) {
    echo(i,j);
}

is the same as

v1 = [1,2,3];
v2 = [4,5,6];
for (i = v1) {
    for (j = v2) {
        echo(i,j);
    }
}

except that the generated tree is subtly different.  (You can't tell unless you look at diagnostic information; it doesn't affect the model.)

You can even write the same thing as:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=j)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Is that just a case of ‘that’s the syntax’ or is there something that is usefully being done by forcing the for() loop to define the variables in what feels to me like a redundant way?


Here you're doing something that works, but can be confusing.

i and j are vectors of two and three elements, respectively.
The for loop walks across those two vectors as in the previous examples, assigning the individual values to *new* i and j.  Those new i and j "hide" the i and j defined earlier.

This is an odd (to me) case:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=i)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }


The same sort of thing is happening, but we need to look at it even more carefully.

i and j start out as the two vectors.

Then a new i is created to step across the old i.
Then a new j is created to step across ... the new i.  By the time that the j=i is examined, the original "i" containing a vector is no longer visible; what is visible is the current value of i as we step along the vector.

Mostly, just don't do this kind of thing.  It will hurt your brain.

 

india = [-0.5,0.5];

juliet = [1,2,3];

 

for (i=india,j=india)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }


Right.  Because nothing is replacing "india".  i steps across india (a vector of two elements), and for each of those elements j steps across india.  (Note that nothing looks at juliet.)

So even though in the for() variable, we first say that i (within the for loop) is i (as defined earlier), saying j=i does not result in an output matching either instance???

 

I find that a bit odd.  No doubt there is a sensible reason for this!


It's all about exactly what happens to the names, in exactly what order.

99% of the answer is "don't assign to a name that's defined in a higher-level block".


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

Re: Bug or my misunderstanding of 'for'?

alexgibson

Thanks all for your input.

 

It seems that having been successfully using for() loops for a long while I had reasonably understood what was actually going on, but was chasing a mirage in terms of shortcuts to writing these for() loops.

 

This has really helped to de-clutter my understanding and get a more solid idea of the mechanics ‘under the bonnet’ of OpenSCAD and why it behaves as it does.  Hope it’s not cluttered your brains too much!

 

So I will just accept that for() can’t immediately use a pre-defined list, but can take it and assign it to a value.  This is still a small benefit to me as I need to run for() over a specific list of values quite often, I can create a named list for the cleanest possible DRY code!

 

Cheers,

 

Alex Gibson

 

admg consulting

 

edumaker limited

 

·         Project management

·         Operations & Process improvement

·         3D Printing

 

From: Jordan Brown [mailto:[hidden email]]
Sent: 18 June 2020 23:23
To: Alex Gibson; 'OpenSCAD general discussion'
Subject: Re: [OpenSCAD] Bug or my misunderstanding of 'for'?

 

On 6/18/2020 10:14 AM, Alex Gibson wrote:

So, while it might be useful and quicker in my use case, it could cause an unacceptable lack of constraint in others!


More that in the general case it wouldn't be a useful interpretation.


At the risk of putting my ignorance of programming languages formation on full display, but in the spirit of ‘don’t repeat yourself’, is there not a shorter way to use a globally defined range of numbers in a for() loop?

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (plus_minus_halves,one_two_three)

                {

                translate([20*plus_minus_halves,40*one_two_three,0])

                cylinder(0.2,15,15);

                }

 

…results in no movement – but also no error!


I suspect that it's an accident that that "for" is not considered to be an error.  What it seems to do is to iterate across the vector(s) without assigning the values to any names.

In the translate, plus_minus_halves and one_two_three are still vectors.  Multiplying a vector by a number is allowed, but what you're then passing to translate is a vector consisting of a two-entry vector, a three-entry vector, and a zero.  That's not a legal input for translate().


Whereas this works, and seems to be saying the same thing…

 

plus_minus_halves = [-0.5,0.5];

one_two_three = [1,2,3];

 

for (i=plus_minus_halves,j=one_two_three)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

That assigns successive values from the vectors to i and j.

Considering the simpler case first:

v = [1,2,3];
for (i = v) {
    echo(i);
}

evaluates the body once for each element in v, setting i equal to that element.  That is, the body is evaluated once with i=1, once with i=2, and once with i=3.

A "for" with multiple values is treated like nested "for"s:

v1 = [1,2,3];
v2 = [4,5,6];
for (i = v1, j = v2) {
    echo(i,j);
}

is the same as

v1 = [1,2,3];
v2 = [4,5,6];
for (i = v1) {
    for (j = v2) {
        echo(i,j);
    }
}

except that the generated tree is subtly different.  (You can't tell unless you look at diagnostic information; it doesn't affect the model.)

You can even write the same thing as:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=j)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }

 

Is that just a case of ‘that’s the syntax’ or is there something that is usefully being done by forcing the for() loop to define the variables in what feels to me like a redundant way?


Here you're doing something that works, but can be confusing.

i and j are vectors of two and three elements, respectively.
The for loop walks across those two vectors as in the previous examples, assigning the individual values to *new* i and j.  Those new i and j "hide" the i and j defined earlier.


This is an odd (to me) case:

 

i = [-0.5,0.5];

j = [1,2,3];

 

for (i=i,j=i)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }


The same sort of thing is happening, but we need to look at it even more carefully.

i and j start out as the two vectors.

Then a new i is created to step across the old i.
Then a new j is created to step across ... the new i.  By the time that the j=i is examined, the original "i" containing a vector is no longer visible; what is visible is the current value of i as we step along the vector.

Mostly, just don't do this kind of thing.  It will hurt your brain.

 

india = [-0.5,0.5];

juliet = [1,2,3];

 

for (i=india,j=india)

                {

                translate([20*i,40*j,0])

                cylinder(0.2,5,5);

                }


Right.  Because nothing is replacing "india".  i steps across india (a vector of two elements), and for each of those elements j steps across india.  (Note that nothing looks at juliet.)


So even though in the for() variable, we first say that i (within the for loop) is i (as defined earlier), saying j=i does not result in an output matching either instance???

 

I find that a bit odd.  No doubt there is a sensible reason for this!


It's all about exactly what happens to the names, in exactly what order.

99% of the answer is "don't assign to a name that's defined in a higher-level block".

 

Virus-free. www.avg.com

 


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