RW
Rogier Wolff
Mon, Oct 5, 2020 3:08 PM
On Mon, Oct 05, 2020 at 03:53:09PM +0200, Torsten Paul wrote:
On 05.10.20 15:20, nop head wrote:
Lazy union also breaks difference when the first argument
is a for loop. Anything after the first iteration gets
subtracted, so another case where explicit union is needed.
As far as I can tell only two unions() needed adding to my
library to fix it.
My preference would be to have it unchanged in behavior, but
maybe with deprecation warnings where needed.
As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.
This IMHO would be complicated: Complicated to do in the code,
complicated to explain to the users.
In Unix the filosophy is that you implement what's an easy-to-use
building block and then allow the users to expand using the building
blocks provided.
So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the right
choice: supplying the \n in the format string is simple and easy, but
the other way around is not: If your printf adds the \n at the end
it is NOT easy to make a printf-without-\n out of that.
So IMHO, a "for" primitive in openscad should NOT do an implicit union
and return one object. It's easy to union the objects with an explicit
union () in front of the for. But not the other way around.
And doing it this way can even be funny to use.
Consider such a puzzle.
https://cdn.shopify.com/s/files/1/0181/8685/products/Crystal_Puzzle.jpg?v=1571438517
(now in this specific puzzle, I'm not sure if the actual puzzle is
equivalent to what I'm suggesting).
If I create a module that returns block number i in the position in
the final puzzle, in the order that the puzzle is assembled.....
(but without the cutouts for to-be-assembled blocks).
for (i=[0:1:NBLOCKS])
difference ()
for (j=[i:1:NBLOCKS])
block(j);
This code is simplified when for does not implicitly union the objects
that for returns. In the current situation it has to be something like:
for (i=[0:1:NBLOCKS])
difference () {
block (i); // this one is the one we're building
for (j=[i+1:1:NBLOCKS]) // but there have to be cutouts for all the future blocks.
block(j);
}
with the for-endpoint-smaller-than-start issue we've discussed
before..... (but for clarity writing it the second way might be a
good idea anyway. I'm torn between the two: I'm a proponent of less
code is good.)
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
On Mon, Oct 05, 2020 at 03:53:09PM +0200, Torsten Paul wrote:
> On 05.10.20 15:20, nop head wrote:
> > Lazy union also breaks difference when the first argument
> > is a for loop. Anything after the first iteration gets
> > subtracted, so another case where explicit union is needed.
> > As far as I can tell only two unions() needed adding to my
> > library to fix it.
>
> My preference would be to have it unchanged in behavior, but
> maybe with deprecation warnings where needed.
>
> As already mentioned, I think the only way to handle those
> cases is to keep the implicit union / child() selection based
> on static "slots". So if the first "slot" of the union is
> a for(), it will still do the union, or if that "slot" is
> accessed via child() then that will return the list of objects
> that for() generated.
This IMHO would be complicated: Complicated to do in the code,
complicated to explain to the users.
In Unix the filosophy is that you implement what's an easy-to-use
building block and then allow the users to expand using the building
blocks provided.
So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the right
choice: supplying the \n in the format string is simple and easy, but
the other way around is not: If your printf adds the \n at the end
it is NOT easy to make a printf-without-\n out of that.
So IMHO, a "for" primitive in openscad should NOT do an implicit union
and return one object. It's easy to union the objects with an explicit
union () in front of the for. But not the other way around.
And doing it this way can even be funny to use.
Consider such a puzzle.
https://cdn.shopify.com/s/files/1/0181/8685/products/Crystal_Puzzle.jpg?v=1571438517
(now in this specific puzzle, I'm not sure if the actual puzzle is
equivalent to what I'm suggesting).
If I create a module that returns block number i in the position in
the final puzzle, in the order that the puzzle is assembled.....
(but without the cutouts for to-be-assembled blocks).
for (i=[0:1:NBLOCKS])
difference ()
for (j=[i:1:NBLOCKS])
block(j);
This code is simplified when for does not implicitly union the objects
that for returns. In the current situation it has to be something like:
for (i=[0:1:NBLOCKS])
difference () {
block (i); // this one is the one we're building
for (j=[i+1:1:NBLOCKS]) // but there have to be cutouts for all the future blocks.
block(j);
}
with the for-endpoint-smaller-than-start issue we've discussed
before..... (but for clarity writing it the second way might be a
good idea anyway. I'm torn between the two: I'm a proponent of less
code is good.)
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
TP
Torsten Paul
Mon, Oct 5, 2020 4:03 PM
On 05.10.20 17:08, Rogier Wolff wrote:
As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.
This IMHO would be complicated: Complicated to do in the code,
complicated to explain to the users.
So far this is the only solution that actually allows
computation of the needed values. That it's currently
a bit awkward to return data structures is a totally
different topic.
https://github.com/openscad/openscad/issues/3143
I'm open to other suggestions which do solve the issue.
ciao,
Torsten.
On 05.10.20 17:08, Rogier Wolff wrote:
>> As already mentioned, I think the only way to handle those
>> cases is to keep the implicit union / child() selection based
>> on static "slots". So if the first "slot" of the union is
>> a for(), it will still do the union, or if that "slot" is
>> accessed via child() then that will return the list of objects
>> that for() generated.
>
> This IMHO would be complicated: Complicated to do in the code,
> complicated to explain to the users.
So far this is the only solution that actually allows
computation of the needed values. That it's currently
a bit awkward to return data structures is a totally
different topic.
https://github.com/openscad/openscad/issues/3143
I'm open to other suggestions which do solve the issue.
ciao,
Torsten.
JB
Jordan Brown
Mon, Oct 5, 2020 4:37 PM
On 10/5/2020 6:53 AM, Torsten Paul wrote:
As already mentioned, I think the only way to handle those cases is to
keep the implicit union / child() selection based on static "slots".
So if the first "slot" of the union is a for(), it will still do the
union, or if that "slot" is accessed via child() then that will return
the list of objects that for() generated.
I think what you're describing would make "implicit union" be an
implementation detail, something that is invisible to the program. Right?
Yes - I think there should be two mostly-separate questions:
(1) When does the geometry engine actually do the unions? I'm not sure
because I don't know beans about the internals, but I don't think this
needs to interact with the user program at all. I suspect that it
could be done while walking the geometry tree to render the final result.
I'm assuming here that the program generates the CSG tree that we
see in Design/Display CSG tree, and then one of the two geometry
engines walks the tree to build the final result. Is that a
reasonably close model?
Note that this behavior could even extend up through explicit
"union" invocations. If there's some reason why union(A,B,C,D) is
better than union(union(A,B),union(C,D)) the geometry engine should
be free to rearrange the expression.
(2) When a module - builtin or otherwise - creates multiple objects,
does its parent see one object, or several? (And the degenerate case of
zero.) This is all on the front end.
(1) should be totally invisible to the program, totally compatible.
(2) is not at all compatible.
On 10/5/2020 6:53 AM, Torsten Paul wrote:
> As already mentioned, I think the only way to handle those cases is to
> keep the implicit union / child() selection based on static "slots".
> So if the first "slot" of the union is a for(), it will still do the
> union, or if that "slot" is accessed via child() then that will return
> the list of objects that for() generated.
I *think* what you're describing would make "implicit union" be an
implementation detail, something that is invisible to the program. Right?
Yes - I think there should be two mostly-separate questions:
(1) When does the geometry engine actually do the unions? I'm not sure
because I don't know beans about the internals, but I don't think this
needs to interact with the user program *at all*. I suspect that it
could be done while walking the geometry tree to render the final result.
I'm assuming here that the program generates the CSG tree that we
see in Design/Display CSG tree, and then one of the two geometry
engines walks the tree to build the final result. Is that a
reasonably close model?
Note that this behavior could even extend up through explicit
"union" invocations. If there's some reason why union(A,B,C,D) is
better than union(union(A,B),union(C,D)) the geometry engine should
be free to rearrange the expression.
(2) When a module - builtin or otherwise - creates multiple objects,
does its parent see one object, or several? (And the degenerate case of
zero.) This is *all* on the front end.
(1) should be totally invisible to the program, totally compatible.
(2) is not at all compatible.
JB
Jordan Brown
Mon, Oct 5, 2020 4:48 PM
On 10/5/2020 8:08 AM, Rogier Wolff wrote:
So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the right
choice: supplying the \n in the format string is simple and easy, but
the other way around is not: If your printf adds the \n at the end it
is NOT easy to make a printf-without-\n out of that.
If it wasn't for the huge number of bugs where programs forget to
include a \n, or include one where it's not appropriate, I'd agree with
you. But people get this wrong all the time. I think it would have
been better to have a function that prints a line (with line
termination, whatever that is) and an otherwise similar function that
prints a partial line without termination. That's what Java did with
print() and println(). I have to bet that Java programs have many fewer
of that class of bugs than C programs, because Java programmers have to
make an explicit and obvious choice. I think Java got it slightly
wrong, by having "print" be the less common form; I think BASIC and sh
got it right by having the printing statement (print, echo) default to
printing a line, and optionally not terminate it.
I think the best strategy is to have the usual case be easy and obvious,
and the advanced case be possible.
On 10/5/2020 8:08 AM, Rogier Wolff wrote:
> So when you get to chose what "printf" does, you can say: most people
> will want the trailing \n, so we'll tack it on for them. Not the right
> choice: supplying the \n in the format string is simple and easy, but
> the other way around is not: If your printf adds the \n at the end it
> is NOT easy to make a printf-without-\n out of that.
If it wasn't for the huge number of bugs where programs forget to
include a \n, or include one where it's not appropriate, I'd agree with
you. But people get this wrong *all* the time. I think it would have
been better to have a function that prints a line (with line
termination, whatever that is) and an otherwise similar function that
prints a partial line without termination. That's what Java did with
print() and println(). I have to bet that Java programs have many fewer
of that class of bugs than C programs, because Java programmers have to
make an explicit and obvious choice. I think Java got it slightly
wrong, by having "print" be the less common form; I think BASIC and sh
got it right by having the printing statement (print, echo) default to
printing a line, and optionally *not* terminate it.
I think the best strategy is to have the usual case be easy and obvious,
and the advanced case be possible.
RW
Rogier Wolff
Mon, Oct 5, 2020 6:47 PM
On Mon, Oct 05, 2020 at 04:48:26PM +0000, Jordan Brown wrote:
On 10/5/2020 8:08 AM, Rogier Wolff wrote:
So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the right
choice: supplying the \n in the format string is simple and easy, but
the other way around is not: If your printf adds the \n at the end it
is NOT easy to make a printf-without-\n out of that.
If it wasn't for the huge number of bugs where programs forget to
include a \n, or include one where it's not appropriate, I'd agree with
you. But people get this wrong all the time. I think it would have
been better to have a function that prints a line (with line
termination, whatever that is) and an otherwise similar function that
prints a partial line without termination. That's what Java did with
print() and println(). I have to bet that Java programs have many fewer
of that class of bugs than C programs, because Java programmers have to
make an explicit and obvious choice. I think Java got it slightly
wrong, by having "print" be the less common form; I think BASIC and sh
got it right by having the printing statement (print, echo) default to
printing a line, and optionally not terminate it.
I think the best strategy is to have the usual case be easy and obvious,
and the advanced case be possible.
In my example of a library function, you can easily provide two variants.
In the case of how to define a language construct you have the restriction
that you have to make ONE choice. That translates back to the library
function example with a restriction: "You are only allowed to provide ONE
function".
In the case of print/println you should then go for "print" as you can
easily define
println (somestring)
{
print (somestring);
print(NEWLINE);
}
in almost all languages and you can (must under the restriction that
the library is only allowed one function) leave that to the user.
With this: "what would we want?" discussion I don't think I can
influence openscad to change to do things right: That would lose
compatibility with older programs, and that's not acceptable. But the
realization: "we should've done it differently is" important: it might
help "design" future modules/operations.
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
On Mon, Oct 05, 2020 at 04:48:26PM +0000, Jordan Brown wrote:
> On 10/5/2020 8:08 AM, Rogier Wolff wrote:
> > So when you get to chose what "printf" does, you can say: most people
> > will want the trailing \n, so we'll tack it on for them. Not the right
> > choice: supplying the \n in the format string is simple and easy, but
> > the other way around is not: If your printf adds the \n at the end it
> > is NOT easy to make a printf-without-\n out of that.
>
> If it wasn't for the huge number of bugs where programs forget to
> include a \n, or include one where it's not appropriate, I'd agree with
> you. But people get this wrong *all* the time. I think it would have
> been better to have a function that prints a line (with line
> termination, whatever that is) and an otherwise similar function that
> prints a partial line without termination. That's what Java did with
> print() and println(). I have to bet that Java programs have many fewer
> of that class of bugs than C programs, because Java programmers have to
> make an explicit and obvious choice. I think Java got it slightly
> wrong, by having "print" be the less common form; I think BASIC and sh
> got it right by having the printing statement (print, echo) default to
> printing a line, and optionally *not* terminate it.
>
> I think the best strategy is to have the usual case be easy and obvious,
> and the advanced case be possible.
In my example of a library function, you can easily provide two variants.
In the case of how to define a language construct you have the restriction
that you have to make ONE choice. That translates back to the library
function example with a restriction: "You are only allowed to provide ONE
function".
In the case of print/println you should then go for "print" as you can
easily define
println (somestring)
{
print (somestring);
print(NEWLINE);
}
in almost all languages and you can (must under the restriction that
the library is only allowed one function) leave that to the user.
With this: "what would we want?" discussion I don't think I can
influence openscad to change to do things right: That would lose
compatibility with older programs, and that's not acceptable. But the
realization: "we should've done it differently is" important: it might
help "design" future modules/operations.
Roger.
--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 **
f equals m times a. When your f is steady, and your m is going down
your a is going up. -- Chris Hadfield about flying up the space shuttle.
A
adrianv
Mon, Oct 5, 2020 8:35 PM
With regards to speed improvements, the one big case I am aware of is calling
hull() on a for loop, the example I posted above. What are other cases
where unnecessary union gets forced, leading to unnecessarily long run
times?
I noticed nophead said he avoids the problem of for() loops in hull() by
unwrapping for() loops. I'll note that this is (1) not always possible and
(2) ugly and annoying to code. But it seems a necessary workaround (when
possible) in the current stable version because of the performance hit. I
have a code that generates polyhedra and I'd rather not unroll the loops for
all of the polyhedra: it would make the code huge, incomprehensible and
unmaintainable. And I'd have to write code to do the unrolling and write
out the unrolled scad code. Of course, another strategy is to avoid
constructing objects with hull(), which I think is a method nophead also
used: he has described the speed up he achieved by recoding his models to
perform all the difficult operations in 2d and avoid 3d operations. One
could argue this is sort of like my approach to making rounded solids: avoid
minkowski and compute the rounded solids directly so I can use polyhedron.
It would be nice if we didn't have to work around limitations this way.
It seems like there are a couple strategies that could be deployed to avoid
breaking compatibility. One would be to introduce a new for loop, call it
split_for() that performs for() without the implicit union. If this was
combined with split_children() to pass the children without a union I think
it would provide the full flexibility to pass objects separately or the old
way. Or I suppose an option flag like for(i=[0:N], union=false) could also
do the job.
Another strategy (that might be impractical to implement---I don't know)
would be to have a second mechanism to access children that accesses the
children without the union. This seems harder to understand and use.
tp3 wrote
On 05.10.20 15:20, nop head wrote:
Lazy union also breaks difference when the first argument
is a for loop. Anything after the first iteration gets
subtracted, so another case where explicit union is needed.
As far as I can tell only two unions() needed adding to my
library to fix it.
My preference would be to have it unchanged in behavior, but
maybe with deprecation warnings where needed.
As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.
Speed doesn't seem much different, two seconds slower
for a 20 minute build, which is just noise. Some things
get faster and some slower.
If I remember correctly, it's not yet available in all places
so it might not reach the full potential. At this point it's
probably affecting mostly cases where the top level union is
the big slow operation.
With regards to speed improvements, the one big case I am aware of is calling
hull() on a for loop, the example I posted above. What are other cases
where unnecessary union gets forced, leading to unnecessarily long run
times?
I noticed nophead said he avoids the problem of for() loops in hull() by
unwrapping for() loops. I'll note that this is (1) not always possible and
(2) ugly and annoying to code. But it seems a necessary workaround (when
possible) in the current stable version because of the performance hit. I
have a code that generates polyhedra and I'd rather not unroll the loops for
all of the polyhedra: it would make the code huge, incomprehensible and
unmaintainable. And I'd have to write code to do the unrolling and write
out the unrolled scad code. Of course, another strategy is to avoid
constructing objects with hull(), which I think is a method nophead also
used: he has described the speed up he achieved by recoding his models to
perform all the difficult operations in 2d and avoid 3d operations. One
could argue this is sort of like my approach to making rounded solids: avoid
minkowski and compute the rounded solids directly so I can use polyhedron.
It would be nice if we didn't have to work around limitations this way.
It seems like there are a couple strategies that could be deployed to avoid
breaking compatibility. One would be to introduce a new for loop, call it
split_for() that performs for() without the implicit union. If this was
combined with split_children() to pass the children without a union I think
it would provide the full flexibility to pass objects separately or the old
way. Or I suppose an option flag like for(i=[0:N], union=false) could also
do the job.
Another strategy (that might be impractical to implement---I don't know)
would be to have a second mechanism to access children that accesses the
children without the union. This seems harder to understand and use.
tp3 wrote
> On 05.10.20 15:20, nop head wrote:
>> Lazy union also breaks difference when the first argument
>> is a for loop. Anything after the first iteration gets
>> subtracted, so another case where explicit union is needed.
>> As far as I can tell only two unions() needed adding to my
>> library to fix it.
>
> My preference would be to have it unchanged in behavior, but
> maybe with deprecation warnings where needed.
>
> As already mentioned, I think the only way to handle those
> cases is to keep the implicit union / child() selection based
> on static "slots". So if the first "slot" of the union is
> a for(), it will still do the union, or if that "slot" is
> accessed via child() then that will return the list of objects
> that for() generated.
>
>> Speed doesn't seem much different, two seconds slower
>> for a 20 minute build, which is just noise. Some things
>> get faster and some slower.
>
> If I remember correctly, it's not yet available in all places
> so it might not reach the full potential. At this point it's
> probably affecting mostly cases where the top level union is
> the big slow operation.
--
Sent from: http://forum.openscad.org/
NH
nop head
Mon, Oct 5, 2020 9:04 PM
There is a fundamental problem with children and for loops that Torsten
linked to above though. If the child is a for loop that isn't unioned then
$children can't be evaluated until the loop has run but with dynamic scoped
variables the loop count might depend on variables in the parent. So you
get a chicken and egg problem.
On Mon, 5 Oct 2020 at 21:36, adrianv avm4@cornell.edu wrote:
With regards to speed improvements, the one big case I am aware of is
calling
hull() on a for loop, the example I posted above. What are other cases
where unnecessary union gets forced, leading to unnecessarily long run
times?
I noticed nophead said he avoids the problem of for() loops in hull() by
unwrapping for() loops. I'll note that this is (1) not always possible and
(2) ugly and annoying to code. But it seems a necessary workaround (when
possible) in the current stable version because of the performance hit. I
have a code that generates polyhedra and I'd rather not unroll the loops
for
all of the polyhedra: it would make the code huge, incomprehensible and
unmaintainable. And I'd have to write code to do the unrolling and write
out the unrolled scad code. Of course, another strategy is to avoid
constructing objects with hull(), which I think is a method nophead also
used: he has described the speed up he achieved by recoding his models to
perform all the difficult operations in 2d and avoid 3d operations. One
could argue this is sort of like my approach to making rounded solids:
avoid
minkowski and compute the rounded solids directly so I can use polyhedron.
It would be nice if we didn't have to work around limitations this way.
It seems like there are a couple strategies that could be deployed to avoid
breaking compatibility. One would be to introduce a new for loop, call it
split_for() that performs for() without the implicit union. If this was
combined with split_children() to pass the children without a union I think
it would provide the full flexibility to pass objects separately or the old
way. Or I suppose an option flag like for(i=[0:N], union=false) could
also
do the job.
Another strategy (that might be impractical to implement---I don't know)
would be to have a second mechanism to access children that accesses the
children without the union. This seems harder to understand and use.
tp3 wrote
On 05.10.20 15:20, nop head wrote:
Lazy union also breaks difference when the first argument
is a for loop. Anything after the first iteration gets
subtracted, so another case where explicit union is needed.
As far as I can tell only two unions() needed adding to my
library to fix it.
My preference would be to have it unchanged in behavior, but
maybe with deprecation warnings where needed.
As already mentioned, I think the only way to handle those
cases is to keep the implicit union / child() selection based
on static "slots". So if the first "slot" of the union is
a for(), it will still do the union, or if that "slot" is
accessed via child() then that will return the list of objects
that for() generated.
Speed doesn't seem much different, two seconds slower
for a 20 minute build, which is just noise. Some things
get faster and some slower.
If I remember correctly, it's not yet available in all places
so it might not reach the full potential. At this point it's
probably affecting mostly cases where the top level union is
the big slow operation.
There is a fundamental problem with children and for loops that Torsten
linked to above though. If the child is a for loop that isn't unioned then
$children can't be evaluated until the loop has run but with dynamic scoped
variables the loop count might depend on variables in the parent. So you
get a chicken and egg problem.
On Mon, 5 Oct 2020 at 21:36, adrianv <avm4@cornell.edu> wrote:
> With regards to speed improvements, the one big case I am aware of is
> calling
> hull() on a for loop, the example I posted above. What are other cases
> where unnecessary union gets forced, leading to unnecessarily long run
> times?
>
> I noticed nophead said he avoids the problem of for() loops in hull() by
> unwrapping for() loops. I'll note that this is (1) not always possible and
> (2) ugly and annoying to code. But it seems a necessary workaround (when
> possible) in the current stable version because of the performance hit. I
> have a code that generates polyhedra and I'd rather not unroll the loops
> for
> all of the polyhedra: it would make the code huge, incomprehensible and
> unmaintainable. And I'd have to write code to do the unrolling and write
> out the unrolled scad code. Of course, another strategy is to avoid
> constructing objects with hull(), which I think is a method nophead also
> used: he has described the speed up he achieved by recoding his models to
> perform all the difficult operations in 2d and avoid 3d operations. One
> could argue this is sort of like my approach to making rounded solids:
> avoid
> minkowski and compute the rounded solids directly so I can use polyhedron.
> It would be nice if we didn't have to work around limitations this way.
>
> It seems like there are a couple strategies that could be deployed to avoid
> breaking compatibility. One would be to introduce a new for loop, call it
> split_for() that performs for() without the implicit union. If this was
> combined with split_children() to pass the children without a union I think
> it would provide the full flexibility to pass objects separately or the old
> way. Or I suppose an option flag like for(i=[0:N], union=false) could
> also
> do the job.
>
> Another strategy (that might be impractical to implement---I don't know)
> would be to have a second mechanism to access children that accesses the
> children without the union. This seems harder to understand and use.
>
>
>
>
> tp3 wrote
> > On 05.10.20 15:20, nop head wrote:
> >> Lazy union also breaks difference when the first argument
> >> is a for loop. Anything after the first iteration gets
> >> subtracted, so another case where explicit union is needed.
> >> As far as I can tell only two unions() needed adding to my
> >> library to fix it.
> >
> > My preference would be to have it unchanged in behavior, but
> > maybe with deprecation warnings where needed.
> >
> > As already mentioned, I think the only way to handle those
> > cases is to keep the implicit union / child() selection based
> > on static "slots". So if the first "slot" of the union is
> > a for(), it will still do the union, or if that "slot" is
> > accessed via child() then that will return the list of objects
> > that for() generated.
> >
> >> Speed doesn't seem much different, two seconds slower
> >> for a 20 minute build, which is just noise. Some things
> >> get faster and some slower.
> >
> > If I remember correctly, it's not yet available in all places
> > so it might not reach the full potential. At this point it's
> > probably affecting mostly cases where the top level union is
> > the big slow operation.
>
>
>
>
>
> --
> Sent from: http://forum.openscad.org/
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
JB
Jordan Brown
Tue, Oct 6, 2020 1:19 AM
On 10/5/2020 11:47 AM, Rogier Wolff wrote:
In the case of how to define a language construct you have the
restriction that you have to make ONE choice. That translates back to
the library function example with a restriction: "You are only allowed
to provide ONE function".
You could do as some other languages (BASIC and sh come to mind) and
have "don't terminate the line" be an option on the print operation.
That is, it could be
print(..., line={true|false})
where the default is true. Or something like that.
In BASIC, a PRINT statement normally terminates the line. When
terminated with a semicolon, it ends without terminating the line.
In UNIX shells, "echo" normally terminates the line. In
Berkeley-derived shells, "echo -n" does not terminate the line; in
AT&T-derived shells a "\c" at the end prevents it from terminating
the line.
With this: "what would we want?" discussion I don't think I can
influence openscad to change to do things right: That would lose
compatibility with older programs, and that's not acceptable. But the
realization: "we should've done it differently is" important: it might
help "design" future modules/operations.
Yes. And in particular a hypothetical printf-like module. (Which I
will try to throw together, but it'll be stretching my C++ skills.)
On 10/5/2020 11:47 AM, Rogier Wolff wrote:
> In the case of how to define a language construct you have the
> restriction that you have to make ONE choice. That translates back to
> the library function example with a restriction: "You are only allowed
> to provide ONE function".
You could do as some other languages (BASIC and sh come to mind) and
have "don't terminate the line" be an option on the print operation.
That is, it could be
print(..., line={true|false})
where the default is true. Or something like that.
In BASIC, a PRINT statement normally terminates the line. When
terminated with a semicolon, it ends without terminating the line.
In UNIX shells, "echo" normally terminates the line. In
Berkeley-derived shells, "echo -n" does not terminate the line; in
AT&T-derived shells a "\c" at the end prevents it from terminating
the line.
> With this: "what would we want?" discussion I don't think I can
> influence openscad to change to do things right: That would lose
> compatibility with older programs, and that's not acceptable. But the
> realization: "we should've done it differently is" important: it might
> help "design" future modules/operations.
Yes. And in particular a hypothetical printf-like module. (Which I
will try to throw together, but it'll be stretching my C++ skills.)
JB
Jordan Brown
Tue, Oct 6, 2020 1:25 AM
On 10/5/2020 2:04 PM, nop head wrote:
There is a fundamental problem with children and for loops that
Torsten linked to above though. If the child is a for loop that isn't
unioned then $children can't be evaluated until the loop has run but
with dynamic scoped variables the loop count might depend on variables
in the parent. So you get a chicken and egg problem.
That's a good point, and a problem with any scheme where a module can
return other than one child - that children aren't executed until they
are referred to. The same problem would apply to an "failing if yields
nothing" scheme.
I don't think - and as usual I'm speaking as somebody who only has a
mental model of how this stuff works, not actual experience with the
guts - that this necessarily affects a lazy union mechanism. A lazy
union mechanism could walk the geometry tree accumulating lists of
objects that need to eventually be unioned, and do the actual union only
when needed for that particular context.
On 10/5/2020 2:04 PM, nop head wrote:
> There is a fundamental problem with children and for loops that
> Torsten linked to above though. If the child is a for loop that isn't
> unioned then $children can't be evaluated until the loop has run but
> with dynamic scoped variables the loop count might depend on variables
> in the parent. So you get a chicken and egg problem.
That's a good point, and a problem with any scheme where a module can
return other than one child - that children aren't executed until they
are referred to. The same problem would apply to an "failing if yields
nothing" scheme.
I don't think - and as usual I'm speaking as somebody who only has a
mental model of how this stuff works, not actual experience with the
guts - that this necessarily affects a lazy union mechanism. A lazy
union mechanism could walk the geometry tree accumulating lists of
objects that need to eventually be unioned, and do the actual union only
when needed for that particular context.
J
jon
Tue, Oct 6, 2020 1:36 PM
Making mistakes and fixing them is part of programming. But I would
prefer a syntax that is easy to read over one that is not. I really dislike
Print(a)
Print(b)
Print(c)
PrintLn()
vs
PrintLn(a, b, c, d)
or
Print(a, b, c, d, \n)
If one cannot find and fix a missing \n, then one probably should find a
hobby (or career) other than programming
IMHO, of course. Goes without saying
On 10/5/2020 12:48 PM, Jordan Brown wrote:
On 10/5/2020 8:08 AM, Rogier Wolff wrote:
So when you get to chose what "printf" does, you can say: most people
will want the trailing \n, so we'll tack it on for them. Not the
right choice: supplying the \n in the format string is simple and
easy, but the other way around is not: If your printf adds the \n at
the end it is NOT easy to make a printf-without-\n out of that.
If it wasn't for the huge number of bugs where programs forget to
include a \n, or include one where it's not appropriate, I'd agree
with you. But people get this wrong all the time. I think it would
have been better to have a function that prints a line (with line
termination, whatever that is) and an otherwise similar function that
prints a partial line without termination. That's what Java did with
print() and println(). I have to bet that Java programs have many
fewer of that class of bugs than C programs, because Java programmers
have to make an explicit and obvious choice. I think Java got it
slightly wrong, by having "print" be the less common form; I think
BASIC and sh got it right by having the printing statement (print,
echo) default to printing a line, and optionally not terminate it.
I think the best strategy is to have the usual case be easy and
obvious, and the advanced case be possible.
OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
Making mistakes and fixing them is part of programming. But I would
prefer a syntax that is easy to read over one that is not. I really dislike
Print(a)
Print(b)
Print(c)
PrintLn()
vs
PrintLn(a, b, c, d)
or
Print(a, b, c, d, \n)
If one cannot find and fix a missing \n, then one probably should find a
hobby (or career) other than programming
IMHO, of course. Goes without saying
On 10/5/2020 12:48 PM, Jordan Brown wrote:
> On 10/5/2020 8:08 AM, Rogier Wolff wrote:
>> So when you get to chose what "printf" does, you can say: most people
>> will want the trailing \n, so we'll tack it on for them. Not the
>> right choice: supplying the \n in the format string is simple and
>> easy, but the other way around is not: If your printf adds the \n at
>> the end it is NOT easy to make a printf-without-\n out of that.
>
> If it wasn't for the huge number of bugs where programs forget to
> include a \n, or include one where it's not appropriate, I'd agree
> with you. But people get this wrong *all* the time. I think it would
> have been better to have a function that prints a line (with line
> termination, whatever that is) and an otherwise similar function that
> prints a partial line without termination. That's what Java did with
> print() and println(). I have to bet that Java programs have many
> fewer of that class of bugs than C programs, because Java programmers
> have to make an explicit and obvious choice. I think Java got it
> slightly wrong, by having "print" be the less common form; I think
> BASIC and sh got it right by having the printing statement (print,
> echo) default to printing a line, and optionally *not* terminate it.
>
> I think the best strategy is to have the usual case be easy and
> obvious, and the advanced case be possible.
>
>
> _______________________________________________
> OpenSCAD mailing list
> Discuss@lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org