discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Why Lazy Union cannot survive in its current form

JB
Jordan Brown
Thu, Sep 24, 2026 6:18 AM

I've said periodically that Lazy Union cannot survive in its current
form, but I'd always been accepting that on faith from others.

Today I was looking into it a bit more deeply as part of my work on a
true multi-color/multi-material solution, and yeah... it can't.  It
produces results that are incompatible with standard OpenSCAD - over and
above the fact that it generates STLs that are arguably invalid.

Consider this program:

intersection() {
     for(x=[-1,1])
         translate([x,0,0]*10)
             sphere(15);
     cube(25, center=true);
}

In standard OpenSCAD, it produces this model:

With Lazy Union enabled, it produces this model:

Not at all the same result.

This is of course a contrived demonstration, demonstrating one of many
scenarios that yield different results in the two modes.

It would be surprising if, among the thousands and thousands of models
out there, there are more than a few that would run into this difference.

Q.  Couldn't it be fixed so that the result is the same?
A.  Sure, but then it wouldn't be Lazy Union in its current form - and
probably some LU-based models would stop working.

Q.  Couldn't it stay as a separate mode?
A.  And have, forever, two different modes with very different behavior,
so that you can't look at a program and tell what it will generate?

Q.  Isn't the LU behavior better?
A.  For reasons too complicated to get into right now (having to do with
children()), I don't think so.  But it doesn't matter, because LU
behavior is not base OpenSCAD's behavior, and breaking models in subtle
ways is highly undesirable.

Q.  Why did it do that?
A.  With LU, the "for" doesn't get implicitly unioned; instead, it stays
separate as two children of the intersection.  The intersection then has
three children (sphere, sphere, cube) that it intersects.  (But:  if you
had to ask, isn't that a problem?)

I've said periodically that Lazy Union cannot survive in its current form, but I'd always been accepting that on faith from others. Today I was looking into it a bit more deeply as part of my work on a true multi-color/multi-material solution, and yeah... it can't.  It produces results that are incompatible with standard OpenSCAD - over and above the fact that it generates STLs that are arguably invalid. Consider this program: intersection() { for(x=[-1,1]) translate([x,0,0]*10) sphere(15); cube(25, center=true); } In standard OpenSCAD, it produces this model: With Lazy Union enabled, it produces this model: Not at all the same result. This is of course a contrived demonstration, demonstrating one of many scenarios that yield different results in the two modes. It would be surprising if, among the thousands and thousands of models out there, there are more than a few that would run into this difference. Q.  Couldn't it be fixed so that the result is the same? A.  Sure, but then it wouldn't be Lazy Union in its current form - and probably some LU-based models would stop working. Q.  Couldn't it stay as a separate mode? A.  And have, forever, two different modes with very different behavior, so that you can't look at a program and tell what it will generate? Q.  Isn't the LU behavior better? A.  For reasons too complicated to get into right now (having to do with children()), I don't think so.  But it doesn't matter, because LU behavior is not base OpenSCAD's behavior, and breaking models in subtle ways is highly undesirable. Q.  Why did it do that? A.  With LU, the "for" doesn't get implicitly unioned; instead, it stays separate as two children of the intersection.  The intersection then has three children (sphere, sphere, cube) that it intersects.  (But:  if you had to ask, isn't that a problem?)
GB
Glenn Butcher
Thu, Sep 24, 2026 2:23 PM

I was an early abuser of lazy-union, did some digging and learned the
fundamental precepts about why this is so.  Yes, the proper thing is to
enforce the concept that a part should be singular in structure, but the
real question to my thinking is, should OpenSCAD allow multiple parts in
a render?  STL doesn't support that, but 3MF does, and for my particular
use case it would be handy to be able to create such in a single script,
name the individual parts, and export them to a multi-mesh 3MF.  Here's
my example:

https://glenn.pulpitrock.net/DRG_163/Models/integration/#model=integration.3mf

This model was created as a set of individual OpenSCAD scripts for each
of the meshes listed in the left-hand pane, and I used a command-line
program I wrote to combine the individual OpenSCAD 3MF exports into a
single 3MF that contains the individual meshes with appropriate names. 
I deployed this to allow folks I work with restoring an old railroad
baggage car to see solutions they were considering in 3D space without
having to install programs to do so.

'lazy-union' is a bit of a distraction from what is probably the
fundamental issue, whether OpenSCAD is to continue as just a workbench
to create models for 3D printing, or extend a bit into larger CAD use cases.

On 9/24/2026 12:18 AM, Jordan Brown via Discuss wrote:

I've said periodically that Lazy Union cannot survive in its current
form, but I'd always been accepting that on faith from others.

Today I was looking into it a bit more deeply as part of my work on a
true multi-color/multi-material solution, and yeah... it can't.  It
produces results that are incompatible with standard OpenSCAD - over
and above the fact that it generates STLs that are arguably invalid.

Consider this program:

 intersection() {
      for(x=[-1,1])
          translate([x,0,0]*10)
              sphere(15);
      cube(25, center=true);
 }

In standard OpenSCAD, it produces this model:

With Lazy Union enabled, it produces this model:

Not at all the same result.

This is of course a contrived demonstration, demonstrating one of many
scenarios that yield different results in the two modes.

It would be surprising if, among the thousands and thousands of models
out there, there are more than a few that would run into this difference.

Q.  Couldn't it be fixed so that the result is the same?
A.  Sure, but then it wouldn't be Lazy Union in its current form - and
probably some LU-based models would stop working.

Q.  Couldn't it stay as a separate mode?
A.  And have, forever, two different modes with very different
behavior, so that you can't look at a program and tell what it will
generate?

Q.  Isn't the LU behavior better?
A.  For reasons too complicated to get into right now (having to do
with children()), I don't think so.  But it doesn't matter, because LU
behavior is not base OpenSCAD's behavior, and breaking models in
subtle ways is highly undesirable.

Q.  Why did it do that?
A.  With LU, the "for" doesn't get implicitly unioned; instead, it
stays separate as two children of the intersection.  The intersection
then has three children (sphere, sphere, cube) that it intersects. 
(But:  if you had to ask, isn't that a problem?)


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

I was an early abuser of lazy-union, did some digging and learned the fundamental precepts about why this is so.  Yes, the proper thing is to enforce the concept that a part should be singular in structure, but the real question to my thinking is, should OpenSCAD allow multiple parts in a render?  STL doesn't support that, but 3MF does, and for my particular use case it would be handy to be able to create such in a single script, name the individual parts, and export them to a multi-mesh 3MF.  Here's my example: https://glenn.pulpitrock.net/DRG_163/Models/integration/#model=integration.3mf This model was created as a set of individual OpenSCAD scripts for each of the meshes listed in the left-hand pane, and I used a command-line program I wrote to combine the individual OpenSCAD 3MF exports into a single 3MF that contains the individual meshes with appropriate names.  I deployed this to allow folks I work with restoring an old railroad baggage car to see solutions they were considering in 3D space without having to install programs to do so. 'lazy-union' is a bit of a distraction from what is probably the fundamental issue, whether OpenSCAD is to continue as just a workbench to create models for 3D printing, or extend a bit into larger CAD use cases. On 9/24/2026 12:18 AM, Jordan Brown via Discuss wrote: > > I've said periodically that Lazy Union cannot survive in its current > form, but I'd always been accepting that on faith from others. > > Today I was looking into it a bit more deeply as part of my work on a > true multi-color/multi-material solution, and yeah... it can't.  It > produces results that are incompatible with standard OpenSCAD - over > and above the fact that it generates STLs that are arguably invalid. > > Consider this program: > > intersection() { > for(x=[-1,1]) > translate([x,0,0]*10) > sphere(15); > cube(25, center=true); > } > > In standard OpenSCAD, it produces this model: > > > > With Lazy Union enabled, it produces this model: > > > Not at all the same result. > > This is of course a contrived demonstration, demonstrating one of many > scenarios that yield different results in the two modes. > > It would be surprising if, among the thousands and thousands of models > out there, there are more than a few that would run into this difference. > > Q.  Couldn't it be fixed so that the result is the same? > A.  Sure, but then it wouldn't be Lazy Union in its current form - and > probably some LU-based models would stop working. > > Q.  Couldn't it stay as a separate mode? > A.  And have, forever, two different modes with very different > behavior, so that you can't look at a program and tell what it will > generate? > > Q.  Isn't the LU behavior better? > A.  For reasons too complicated to get into right now (having to do > with children()), I don't think so.  But it doesn't matter, because LU > behavior is not base OpenSCAD's behavior, and breaking models in > subtle ways is highly undesirable. > > Q.  Why did it do that? > A.  With LU, the "for" doesn't get implicitly unioned; instead, it > stays separate as two children of the intersection.  The intersection > then has three children (sphere, sphere, cube) that it intersects.  > (But:  if you had to ask, isn't that a problem?) > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Thu, Sep 24, 2026 3:49 PM

On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote:

but the real question to my thinking is, should OpenSCAD allow
multiple parts in a render?

Absolutely it should, or it will become irrelevant.  Multicolor printing
requires it, and multicolor printing has been consumer-grade for a while
and is getting more so.  My point is only that Lazy Union, without
significant change, is not the path.

On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote: > > but the real question to my thinking is, should OpenSCAD allow > multiple parts in a render? > Absolutely it should, or it will become irrelevant.  Multicolor printing requires it, and multicolor printing has been consumer-grade for a while and is getting more so.  My point is only that Lazy Union, without significant change, is not the path.
JL
Jamie Larkby-Lahet
Thu, Sep 24, 2026 5:24 PM

another way of looking at it would be that the implicit unions in various
parts of openscad are the issue, no?

if every union was explicit, then presumably behavior would be predictable.
for example, using intersection_for() in Jordan's example achieved the lazy
union result in standard openscad. and wrapping the for() in a translate()
'fixes'/'breaks' the lazy union result.

another way to think about this is that openscad doesn't have an explicit
way to collect objects (and keep them separated). children() allows access,
but there is afaik no way to pass this set through to a caller without an
implicit union.

and of course object collections seems to me to be related to the idea of
object references, though admittedly, it doesn't strictly have to be.

but my thought is that if openscad had an explicit object collection, that
is never implicitly unioned, even as standard objects alongside it are, we
could keep the standard behavior and have a way to mimic the somewhat
haphazard benefit of lazy union in an explicit way, that can't be thrown
off by a stray translate().

of course an object collection would need an explicit way to union its
contents, but that could be the standard union() operator, or it could be a
special collection_union() operator, which along with an is_collection()
function, would let the oblivious remain safely oblivious and in the places
where it truly matters the correct behavior could be enforced.

On Thu, Sep 24, 2026, 10:49 Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:

On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote:

but the real question to my thinking is, should OpenSCAD allow
multiple parts in a render?

Absolutely it should, or it will become irrelevant.  Multicolor printing
requires it, and multicolor printing has been consumer-grade for a while
and is getting more so.  My point is only that Lazy Union, without
significant change, is not the path.


OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org

another way of looking at it would be that the implicit unions in various parts of openscad are the issue, no? if every union was explicit, then presumably behavior would be predictable. for example, using intersection_for() in Jordan's example achieved the lazy union result in standard openscad. and wrapping the for() in a translate() 'fixes'/'breaks' the lazy union result. another way to think about this is that openscad doesn't have an explicit way to collect objects (and keep them separated). children() allows access, but there is afaik no way to pass this set through to a caller without an implicit union. and of course object collections seems to me to be related to the idea of object references, though admittedly, it doesn't strictly have to be. but my thought is that if openscad had an explicit object collection, that is never implicitly unioned, even as standard objects alongside it are, we could keep the standard behavior and have a way to mimic the somewhat haphazard benefit of lazy union in an explicit way, that can't be thrown off by a stray translate(). of course an object collection would need an explicit way to union its contents, but that could be the standard union() operator, or it could be a special collection_union() operator, which along with an is_collection() function, would let the oblivious remain safely oblivious and in the places where it truly matters the correct behavior could be enforced. On Thu, Sep 24, 2026, 10:49 Jordan Brown via Discuss < discuss@lists.openscad.org> wrote: > On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote: > > > > but the real question to my thinking is, should OpenSCAD allow > > multiple parts in a render? > > > Absolutely it should, or it will become irrelevant. Multicolor printing > requires it, and multicolor printing has been consumer-grade for a while > and is getting more so. My point is only that Lazy Union, without > significant change, is not the path. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
JB
Jordan Brown
Thu, Sep 24, 2026 10:00 PM

On 9/24/2026 11:24 AM, Jamie Larkby-Lahet via Discuss wrote:

another way of looking at it would be that the implicit unions in
various parts of openscad are the issue, no?

I did pre-emptively answer that:

Q.  Isn't the LU behavior better?
A.  For reasons too complicated to get into right now (having to do
with children()), I don't think so.  But it doesn't matter, because
LU behavior is not base OpenSCAD's behavior, and breaking models in
subtle ways is highly undesirable.

if every union was explicit,

Sure.  But there are many years, thousands of users, and thousands of
models that say that it isn't.

translate(...) { cube(); sphere(); } either implicitly unions, or
doesn't.  And existing practice is that it doesn't.

One could imagine an operator that did not implicitly union its
children, that collected them up in a list and returned that list, which
was then not implicitly unioned.  Something like

translate() list() { cube(); sphere; }

... but that wouldn't be LU in its current form, and I'm don't think
that it's as useful as one might think.  And of course it's not getting
rid of implicit union - rather, it's a way to explicitly not-union.

Offhand I come up with two reasons why it would be less than ideally
useful...

  • Sure, now you have a list of two components.  Two unnamed
    components, with no additional metadata identifying them or saying
    anything about how they should be treated..  That's not very helpful
    when it comes time to assign treatment to each of them in a slicer.
  • One of the key issues with implicit union is that there's no way to
    pass a list of shapes back to your parent and have the parent handle
    them independently.  And this mechanism (like LU) doesn't address
    that issue.  The immediate problem is a chicken-and-egg problem: 
    $children tells the parent how many children there are, and must be
    available before the children run... and therefore before the number
    of "dynamic" children is known.  It's at least a bit hard to come up
    with a scheme that lets you independently process each of those
    "grandchildren".
    o One scheme would use PR#4478's geometry values, because then you
    can straightforwardly pass around lists of shapes, but that's a
    pretty ambitious extension.

My proposal for multi-part design, OEP9
https://github.com/openscad/openscad/wiki/OEP9:-Generating-Multiple-%E2%80%9CParts%E2%80%9D-in-One-Run,
takes a related approach to the first of those two problems. However,
rather than having a way to say "here is a list" it has a way to say
"here is a separate part".  Because it explicitly calls out the separate
part, it has a place to hook on a name and additional metadata.  In a
way, what's returned is sort of list-like, in that each point in the
tree could have several distinct parts returned.  That proposal does not
attempt to address the second concern above.

On 9/24/2026 11:24 AM, Jamie Larkby-Lahet via Discuss wrote: > another way of looking at it would be that the implicit unions in > various parts of openscad are the issue, no? I did pre-emptively answer that: Q.  Isn't the LU behavior better? A.  For reasons too complicated to get into right now (having to do with children()), I don't think so.  But it doesn't matter, because LU behavior is not base OpenSCAD's behavior, and breaking models in subtle ways is highly undesirable. > if every union was explicit, Sure.  But there are many years, thousands of users, and thousands of models that say that it isn't. translate(...) { cube(); sphere(); } either implicitly unions, or doesn't.  And existing practice is that it doesn't. One could imagine an operator that did not implicitly union its children, that collected them up in a list and returned that list, which was then not implicitly unioned.  Something like translate() list() { cube(); sphere; } ... but that wouldn't be LU in its current form, and I'm don't think that it's as useful as one might think.  And of course it's not getting rid of implicit union - rather, it's a way to explicitly not-union. Offhand I come up with two reasons why it would be less than ideally useful... * Sure, now you have a list of two components.  Two *unnamed* components, with no additional metadata identifying them or saying anything about how they should be treated..  That's not very helpful when it comes time to assign treatment to each of them in a slicer. * One of the key issues with implicit union is that there's no way to pass a list of shapes back to your parent and have the parent handle them independently.  And this mechanism (like LU) doesn't address that issue.  The immediate problem is a chicken-and-egg problem:  $children tells the parent how many children there are, and must be available before the children run... and therefore before the number of "dynamic" children is known.  It's at least a bit hard to come up with a scheme that lets you independently process each of those "grandchildren". o One scheme would use PR#4478's geometry values, because then you can straightforwardly pass around lists of shapes, but that's a pretty ambitious extension. My proposal for multi-part design, OEP9 <https://github.com/openscad/openscad/wiki/OEP9:-Generating-Multiple-%E2%80%9CParts%E2%80%9D-in-One-Run>, takes a related approach to the first of those two problems. However, rather than having a way to say "here is a list" it has a way to say "here is a separate part".  Because it explicitly calls out the separate part, it has a place to hook on a name and additional metadata.  In a way, what's returned is sort of list-like, in that each point in the tree could have several distinct parts returned.  That proposal does not attempt to address the second concern above.
CC
Cory Cross
Thu, Sep 24, 2026 11:30 PM

On 9/24/26 8:49 AM, Jordan Brown via Discuss wrote:

On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote:

but the real question to my thinking is, should OpenSCAD allow
multiple parts in a render?

Absolutely it should, or it will become irrelevant.  Multicolor
printing requires it, and multicolor printing has been consumer-grade
for a while and is getting more so.  My point is only that Lazy Union,
without significant change, is not the path.

I posted this in the github issue, but this can be done by preserving
lazy union at the top-level only and eliminating how it affects for or
any other computations. This is always language-compatible, because the
language cannot observe the top level. In fact, it can just be an export
option for 3mf. For STL, the current LU behaviour is to create a
non-manifold output if you have overlapping top objects, so that's a
pretty bad default and it would be better to just union it IMNSHO.

I can't speak for the maintainers, but I would be surprised if someone
put this in as a new experimental feature and it didn't get accepted.

Cory

On 9/24/26 8:49 AM, Jordan Brown via Discuss wrote: > On 9/24/2026 7:23 AM, Glenn Butcher via Discuss wrote: >> >> but the real question to my thinking is, should OpenSCAD allow >> multiple parts in a render? >> > Absolutely it should, or it will become irrelevant.  Multicolor > printing requires it, and multicolor printing has been consumer-grade > for a while and is getting more so.  My point is only that Lazy Union, > without significant change, is not the path. > I posted this in the github issue, but this can be done by preserving lazy union at the top-level only and eliminating how it affects `for` or any other computations. This is always language-compatible, because the language cannot observe the top level. In fact, it can just be an export option for 3mf. For STL, the current LU behaviour is to create a non-manifold output if you have overlapping top objects, so that's a pretty bad default and it would be better to just union it IMNSHO. I can't speak for the maintainers, but I would be surprised if someone put this in as a new experimental feature and it didn't get accepted. Cory
ME
maurice e heskett
Fri, Sep 25, 2026 12:16 AM

On 9/24/26 10:27, Glenn Butcher via Discuss wrote:

I was an early abuser of lazy-union, did some digging and learned the
fundamental precepts about why this is so.  Yes, the proper thing is
to enforce the concept that a part should be singular in structure,
but the real question to my thinking is, should OpenSCAD allow
multiple parts in a render?  STL doesn't support that, but 3MF does,
and for my particular use case it would be handy to be able to create
such in a single script, name the individual parts, and export them to
a multi-mesh 3MF. Here's my example:

https://glenn.pulpitrock.net/DRG_163/Models/integration/#model=integration.3mf

This model was created as a set of individual OpenSCAD scripts for
each of the meshes listed in the left-hand pane, and I used a
command-line program I wrote to combine the individual OpenSCAD 3MF
exports into a single 3MF that contains the individual meshes with
appropriate names.  I deployed this to allow folks I work with
restoring an old railroad baggage car to see solutions they were
considering in 3D space without having to install programs to do so.

'lazy-union' is a bit of a distraction from what is probably the
fundamental issue, whether OpenSCAD is to continue as just a workbench
to create models for 3D printing, or extend a bit into larger CAD use
cases.

I have not used it since it seems to be hidden under a basket,
un-mentioned anyplace in the docs I have.

On 9/24/2026 12:18 AM, Jordan Brown via Discuss wrote:

I've said periodically that Lazy Union cannot survive in its current
form, but I'd always been accepting that on faith from others.

Today I was looking into it a bit more deeply as part of my work on a
true multi-color/multi-material solution, and yeah... it can't.  It
produces results that are incompatible with standard OpenSCAD - over
and above the fact that it generates STLs that are arguably invalid.

Consider this program:

 intersection() {
      for(x=[-1,1])
          translate([x,0,0]*10)
              sphere(15);
      cube(25, center=true);
 }

In standard OpenSCAD, it produces this model:

With Lazy Union enabled, it produces this model:

Not at all the same result.

This is of course a contrived demonstration, demonstrating one of
many scenarios that yield different results in the two modes.

It would be surprising if, among the thousands and thousands of
models out there, there are more than a few that would run into this
difference.

Q.  Couldn't it be fixed so that the result is the same?
A.  Sure, but then it wouldn't be Lazy Union in its current form -
and probably some LU-based models would stop working.

Q.  Couldn't it stay as a separate mode?
A.  And have, forever, two different modes with very different
behavior, so that you can't look at a program and tell what it will
generate?

Q.  Isn't the LU behavior better?
A.  For reasons too complicated to get into right now (having to do
with children()), I don't think so.  But it doesn't matter, because
LU behavior is not base OpenSCAD's behavior, and breaking models in
subtle ways is highly undesirable.

Q.  Why did it do that?
A.  With LU, the "for" doesn't get implicitly unioned; instead, it
stays separate as two children of the intersection.  The intersection
then has three children (sphere, sphere, cube) that it intersects. 
(But:  if you had to ask, isn't that a problem?)

It would seem so to me. I see the first render as a possible mistaken
use of "scope".  Probably because I don't always understand it myself. 
Perhaps some educational conversation is indicated?  So far, everything
I have done hasn't used BOSL2 but once.

Cheers, Gene.


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org


OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org

On 9/24/26 10:27, Glenn Butcher via Discuss wrote: > > I was an early abuser of lazy-union, did some digging and learned the > fundamental precepts about why this is so.  Yes, the proper thing is > to enforce the concept that a part should be singular in structure, > but the real question to my thinking is, should OpenSCAD allow > multiple parts in a render?  STL doesn't support that, but 3MF does, > and for my particular use case it would be handy to be able to create > such in a single script, name the individual parts, and export them to > a multi-mesh 3MF. Here's my example: > > https://glenn.pulpitrock.net/DRG_163/Models/integration/#model=integration.3mf > > This model was created as a set of individual OpenSCAD scripts for > each of the meshes listed in the left-hand pane, and I used a > command-line program I wrote to combine the individual OpenSCAD 3MF > exports into a single 3MF that contains the individual meshes with > appropriate names.  I deployed this to allow folks I work with > restoring an old railroad baggage car to see solutions they were > considering in 3D space without having to install programs to do so. > > 'lazy-union' is a bit of a distraction from what is probably the > fundamental issue, whether OpenSCAD is to continue as just a workbench > to create models for 3D printing, or extend a bit into larger CAD use > cases. > I have not used it since it seems to be hidden under a basket, un-mentioned anyplace in the docs I have. > On 9/24/2026 12:18 AM, Jordan Brown via Discuss wrote: >> >> I've said periodically that Lazy Union cannot survive in its current >> form, but I'd always been accepting that on faith from others. >> >> Today I was looking into it a bit more deeply as part of my work on a >> true multi-color/multi-material solution, and yeah... it can't.  It >> produces results that are incompatible with standard OpenSCAD - over >> and above the fact that it generates STLs that are arguably invalid. >> >> Consider this program: >> >> intersection() { >> for(x=[-1,1]) >> translate([x,0,0]*10) >> sphere(15); >> cube(25, center=true); >> } >> >> In standard OpenSCAD, it produces this model: >> >> >> >> With Lazy Union enabled, it produces this model: >> >> >> Not at all the same result. >> >> This is of course a contrived demonstration, demonstrating one of >> many scenarios that yield different results in the two modes. >> >> It would be surprising if, among the thousands and thousands of >> models out there, there are more than a few that would run into this >> difference. >> >> Q.  Couldn't it be fixed so that the result is the same? >> A.  Sure, but then it wouldn't be Lazy Union in its current form - >> and probably some LU-based models would stop working. >> >> Q.  Couldn't it stay as a separate mode? >> A.  And have, forever, two different modes with very different >> behavior, so that you can't look at a program and tell what it will >> generate? >> >> Q.  Isn't the LU behavior better? >> A.  For reasons too complicated to get into right now (having to do >> with children()), I don't think so.  But it doesn't matter, because >> LU behavior is not base OpenSCAD's behavior, and breaking models in >> subtle ways is highly undesirable. >> >> Q.  Why did it do that? >> A.  With LU, the "for" doesn't get implicitly unioned; instead, it >> stays separate as two children of the intersection.  The intersection >> then has three children (sphere, sphere, cube) that it intersects.  >> (But:  if you had to ask, isn't that a problem?) >> It would seem so to me. I see the first render as a possible mistaken use of "scope".  Probably because I don't always understand it myself.  Perhaps some educational conversation is indicated?  So far, everything I have done hasn't used BOSL2 but once. Cheers, Gene. >> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email todiscuss-leave@lists.openscad.org > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
JB
Jordan Brown
Fri, Sep 25, 2026 1:45 AM

On 9/24/2026 5:30 PM, Cory Cross via Discuss wrote:

I posted this in the github issue, but this can be done by preserving
lazy union at the top-level only and eliminating how it affects for
or any other computations. This is always language-compatible, because
the language cannot observe the top level.

Preserving LU at the top level only would of course be incompatible with
its existing behavior.  But it would also be a remarkably poor solution
to multicolor/multimaterial and related problems.  The components are
not named, so you can't easily match up slicer settings with parts. 
You'd have to pick them off the the preview or just know what order they
will be in; you couldn't safely statically tie slicer settings to them. 
There's no way to add metadata to a part, and so no hope that you can
say "red" and have the slicer automatically pick the extruder that it's
been told has red loaded.

In fact, it can just be an export option for 3mf. For STL, the current
LU behaviour is to create a non-manifold output if you have
overlapping top objects, so that's a pretty bad default and it would
be better to just union it IMNSHO.

Perhaps, except for the fact that current OpenSCAD architecture has the
"render" and "export" steps separate.  If it's unioned in the render,
there's no way to split it in the export, and vice versa.  (Yes, the
export could go back and do the final union, or the render could leave
around both before and after the final union, but... bleah.)

I can't speak for the maintainers, but I would be surprised if someone
put this in as a new experimental feature and it didn't get accepted.

I'm not 100% clear on which "this" you're talking about, but if you mean
LU as it exists today... my understanding is that it wasn't intended as
an important-to-users feature.  It was intended as an optimization,
reducing render time by skipping the (usually-expensive) final union and
emitting a model that most slicers could still handle.  Manifold has
mostly addressed the optimization need, and its other warts make it
undesirable.  (Or at least that's my understanding of the feeling.)

I'm not saying that LU will go away any time soon.  People are known to
be (ab)using it for multicolor/multimaterial design. Even if a new
first-class-citizen scheme is introduced, my bet is that LU won't go
away immediately.  However, it's pretty clear to me that it won't be the
basis for a new first-class-citizen multicolor/multimaterial scheme.

On 9/24/2026 5:30 PM, Cory Cross via Discuss wrote: > I posted this in the github issue, but this can be done by preserving > lazy union at the top-level only and eliminating how it affects `for` > or any other computations. This is always language-compatible, because > the language cannot observe the top level. Preserving LU at the top level only would of course be incompatible with its existing behavior.  But it would also be a remarkably poor solution to multicolor/multimaterial and related problems.  The components are not named, so you can't easily match up slicer settings with parts.  You'd have to pick them off the the preview or just know what order they will be in; you couldn't safely statically tie slicer settings to them.  There's no way to add metadata to a part, and so no hope that you can say "red" and have the slicer automatically pick the extruder that it's been told has red loaded. > In fact, it can just be an export option for 3mf. For STL, the current > LU behaviour is to create a non-manifold output if you have > overlapping top objects, so that's a pretty bad default and it would > be better to just union it IMNSHO. Perhaps, except for the fact that current OpenSCAD architecture has the "render" and "export" steps separate.  If it's unioned in the render, there's no way to split it in the export, and vice versa.  (Yes, the export could go back and do the final union, or the render could leave around both before and after the final union, but... bleah.) > I can't speak for the maintainers, but I would be surprised if someone > put this in as a new experimental feature and it didn't get accepted. I'm not 100% clear on which "this" you're talking about, but if you mean LU as it exists today... my understanding is that it wasn't intended as an important-to-users feature.  It was intended as an optimization, reducing render time by skipping the (usually-expensive) final union and emitting a model that most slicers could still handle.  Manifold has mostly addressed the optimization need, and its other warts make it undesirable.  (Or at least that's my understanding of the feeling.) I'm not saying that LU will go away any time soon.  People are known to be (ab)using it for multicolor/multimaterial design. Even if a new first-class-citizen scheme is introduced, my bet is that LU won't go away immediately.  However, it's pretty clear to me that it won't be the basis for a new first-class-citizen multicolor/multimaterial scheme.
JB
Jordan Brown
Fri, Sep 25, 2026 2:23 AM

Gene asked for more of a discussion of the example that I gave as
problematic for Lazy Union.

I had said:

Q.  Why did it do that?
A.  With LU, the "for" doesn't get implicitly unioned; instead, it
stays separate as two children of the intersection.  The
intersection then has three children (sphere, sphere, cube) that it
intersects.  (But:  if you had to ask, isn't that a problem?)

and Gene said:

It would seem so to me. I see the first render as a possible mistaken
use of "scope".  Probably because I don't always understand it
myself.  Perhaps some educational conversation is indicated?  So far,
everything I have done hasn't used BOSL2 but once.

There's no BOSL2 in this picture, but I'm happy to go through it in more
detail.

Here's the example again:

intersection() {
     for(x=[-1,1])
         translate([x,0,0]*10)
             sphere(15);
     cube(25, center=true);
}

Here's its result in standard OpenSCAD:

Why does it get that result?

The "for" loop generates two spheres, which are implicitly unioned so
that there's one "two spheres mushed into each other" shape:

The intersection then intersects that sort-of-dumbell-shaped shape with
a centered cube, chopping off the top, bottom, front, back, left, and
right sides.  Highlighting the cube with #:

Now, to be clear:  is this particular model useful for anything real? 
Eh, probably not.  It's a contrived, simple example.  But are there more
complex variants that might well appear in a "real" model?  I think so. 
For instance, a cross-section might well involve a very similar
construct.  Or maybe an artistic intersection of an array of shapes with
another shape.  I'll give a couple of examples at the end.

The point of the message was that with Lazy Union enabled, the results
of the "for" are not implicitly unioned, and the result is as if you'd
said

intersection() {
     translate([-10,0,0])
         sphere(15);

     translate([10,0,0])
         sphere(15);

     cube(25, center=true);
}

Intersecting the two spheres, highlighting one of them, yields this:

and then intersecting with the cube doesn't change anything, because the
cube (highlighted) is larger than that:


I promised a couple of perhaps-more-realistic models.  I'm not
explaining them in detail, but I hope that you can see how they relate
to my original simple example.

Mightn't something like this (an intersection of an array of spheres
with a cube) show up in an artistic model?

Or something like this (an intersection of an array of cubes with a sphere)?

Or, again simplified, this sort of cross-section cut?  This particular
example does not use intersection; it demonstrates a related problem
with difference; the LU result is:

Gene asked for more of a discussion of the example that I gave as problematic for Lazy Union. I had said: Q.  Why did it do that? A.  With LU, the "for" doesn't get implicitly unioned; instead, it stays separate as two children of the intersection.  The intersection then has three children (sphere, sphere, cube) that it intersects.  (But:  if you had to ask, isn't that a problem?) and Gene said: > It would seem so to me. I see the first render as a possible mistaken > use of "scope".  Probably because I don't always understand it > myself.  Perhaps some educational conversation is indicated?  So far, > everything I have done hasn't used BOSL2 but once. There's no BOSL2 in this picture, but I'm happy to go through it in more detail. Here's the example again: intersection() { for(x=[-1,1]) translate([x,0,0]*10) sphere(15); cube(25, center=true); } Here's its result in standard OpenSCAD: Why does it get that result? The "for" loop generates two spheres, which are implicitly unioned so that there's one "two spheres mushed into each other" shape: The intersection then intersects that sort-of-dumbell-shaped shape with a centered cube, chopping off the top, bottom, front, back, left, and right sides.  Highlighting the cube with #: Now, to be clear:  is this particular model useful for anything real?  Eh, probably not.  It's a contrived, simple example.  But are there more complex variants that might well appear in a "real" model?  I think so.  For instance, a cross-section might well involve a very similar construct.  Or maybe an artistic intersection of an array of shapes with another shape.  I'll give a couple of examples at the end. The point of the message was that with Lazy Union enabled, the results of the "for" are *not* implicitly unioned, and the result is as if you'd said intersection() { translate([-10,0,0]) sphere(15); translate([10,0,0]) sphere(15); cube(25, center=true); } Intersecting the two spheres, highlighting one of them, yields this: and then intersecting with the cube doesn't change anything, because the cube (highlighted) is larger than that: --- I promised a couple of perhaps-more-realistic models.  I'm not explaining them in detail, but I hope that you can see how they relate to my original simple example. Mightn't something like this (an intersection of an array of spheres with a cube) show up in an artistic model? Or something like this (an intersection of an array of cubes with a sphere)? Or, again simplified, this sort of cross-section cut?  This particular example does not use intersection; it demonstrates a related problem with difference; the LU result is:
JB
Jordan Brown
Fri, Sep 25, 2026 2:34 AM

On 9/24/2026 7:45 PM, Jordan Brown via Discuss wrote:

I'm not 100% clear on which "this" you're talking about, but if you
mean LU as it exists today... my understanding is that it wasn't
intended as an important-to-users feature.  It was intended as an
optimization, reducing render time by skipping the (usually-expensive)
final union and emitting a model that most slicers could still
handle.  Manifold has mostly addressed the optimization need, and its
other warts make it undesirable.  (Or at least that's my understanding
of the feeling.)

Rereading the history when it was introduced, there was a note that it
might be useful for multicolor/multimaterial work, though indeed the
emphasis appeared to be on performance.

On 9/24/2026 7:45 PM, Jordan Brown via Discuss wrote: > I'm not 100% clear on which "this" you're talking about, but if you > mean LU as it exists today... my understanding is that it wasn't > intended as an important-to-users feature.  It was intended as an > optimization, reducing render time by skipping the (usually-expensive) > final union and emitting a model that most slicers could still > handle.  Manifold has mostly addressed the optimization need, and its > other warts make it undesirable.  (Or at least that's my understanding > of the feeling.) Rereading the history when it was introduced, there *was* a note that it might be useful for multicolor/multimaterial work, though indeed the emphasis appeared to be on performance.