Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton fatherhorton@gmail.com
wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations around the x, y and
z axes?
An additional constraint: my probably-wrong intuition says you should be
able to do it with no more than three rotations, zero or one in each of the
axes. (-45 rotations are OK.) That's a fairly small number; maybe I'll
put it together.
Note as an aside, is there no way to increase allowed recursion depth?
If I set the max much higher it fails with "recursion detected" (like I
didn't know).
At least one of the limits, maybe the only limit, is based on the
compiled-in C++ stack size. OpenSCAD recursion translates into C++
recursion, so that's a hard limit. (But: I don't know about the APIs
involved here, but at least some thread APIs let you specify the stack size
for newly created threads, so that might allow for customization.)
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
That's why I put a question mark. I don't know.
On Thu, Jan 22, 2026 at 4:54 PM Adrian Mariano avm4@cornell.edu wrote:
Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton fatherhorton@gmail.com
wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations around the x, y and
z axes?
An additional constraint: my probably-wrong intuition says you should
be able to do it with no more than three rotations, zero or one in each of
the axes. (-45 rotations are OK.) That's a fairly small number; maybe
I'll put it together.
Note as an aside, is there no way to increase allowed recursion depth?
If I set the max much higher it fails with "recursion detected" (like I
didn't know).
At least one of the limits, maybe the only limit, is based on the
compiled-in C++ stack size. OpenSCAD recursion translates into C++
recursion, so that's a hard limit. (But: I don't know about the APIs
involved here, but at least some thread APIs let you specify the stack size
for newly created threads, so that might allow for customization.)
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Evidently not, as drawpt is eligible for tail recursion as written.
On 1/22/26 15:15, Father Horton via Discuss wrote:
That's why I put a question mark. I don't know.
On Thu, Jan 22, 2026 at 4:54 PM Adrian Mariano avm4@cornell.edu wrote:
Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton
<fatherhorton@gmail.com> wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss
<discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations
around the x, y and z axes?
An additional constraint: my probably-wrong intuition
says you should be able to do it with no more than three
rotations, zero or one in each of the axes. (-45
rotations are OK.) That's a fairly small number; maybe
I'll put it together.
Note as an aside, is there no way to increase allowed
recursion depth? If I set the max much higher it fails
with "recursion detected" (like I didn't know).
At least one of the limits, maybe the only limit, is based
on the compiled-in C++ stack size. OpenSCAD recursion
translates into C++ recursion, so that's a hard limit.
(But: I don't know about the APIs involved here, but at
least some thread APIs let you specify the stack size for
newly created threads, so that might allow for customization.)
Haha. The grand wizard around here is Adrian!
I was able to further obfuscate my solution. Gemini figured out the (1 +
sqrt(3)) / 3) part to remove one translate(). Then I figured out how to
remove three more translate()s, having had to /guess/ the sqrt(2):
difference() {
union() { cube([2, 1, 1]); cube([1, 1, 2]); }
translate(2 * [sqrt(2), (1 + sqrt(3)) / 3, (1 + sqrt(3)) / 3])
rotate([0, atan(sqrt(2)), 45]) cube(4, center=true);
}
difference() {
cube([2, 2, 1]);
translate([1, 0, 1]) rotate([0, 45, 0]) cube(3);
}
-Curt
On 1/22/26 01:49, Guenther Sohler via Discuss wrote:
Hey, that's an awesome short.
you are an absolute geometry wizard :)
On Thu, Jan 22, 2026 at 10:44 AM Curt McDowell via Discuss
discuss@lists.openscad.org wrote:
Here's my entry. Although it's vanilla code, it's just about as
readable as a polyhedron()!
difference() {
union() {
translate([-1, 0, 0]) cube([2, 1, 1]);
translate([-1, 0, 1]) cube(1);
}
translate([1, 1, 1] * 2 / 3)
rotate([0, atan(sqrt(2)), 45])
translate([-2, -2, 0]) cube(4);
}
difference() {
translate([-1, 1, 0]) cube([2, 1, 1]);
translate([0, 0, 1]) rotate([0, 45, 0]) cube(3);
}
The last statement in drawpt is an if() statement, not a recursion. But I
suspect that modules don't give special handling to tail recursion, even if
more generously interpreted. I think it's not something that people
normally try to do---thousands deep recursion in a module. My application
here is rather weird and there's probably a better way to approach the
problem of exploring the group generated by 45 deg rotations. I just took
a quick/lazy one, figuring that if there was some structure it might pop
out. It could be rewritten as a function that computes all the points.
That would get tail recursion, and then you could run arbitrarily many
points. And you could check how close the best match is to [1,1,1]. But
for the picture, looping drawpt() isn't an inferior choice, in terms of
quality of the result.
On Thu, Jan 22, 2026 at 6:42 PM Curt McDowell via Discuss <
discuss@lists.openscad.org> wrote:
Evidently not, as drawpt is eligible for tail recursion as written.
On 1/22/26 15:15, Father Horton via Discuss wrote:
That's why I put a question mark. I don't know.
On Thu, Jan 22, 2026 at 4:54 PM Adrian Mariano avm4@cornell.edu wrote:
Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton fatherhorton@gmail.com
wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations around the x, y
and z axes?
An additional constraint: my probably-wrong intuition says you should
be able to do it with no more than three rotations, zero or one in each of
the axes. (-45 rotations are OK.) That's a fairly small number; maybe
I'll put it together.
Note as an aside, is there no way to increase allowed recursion depth?
If I set the max much higher it fails with "recursion detected" (like I
didn't know).
At least one of the limits, maybe the only limit, is based on the
compiled-in C++ stack size. OpenSCAD recursion translates into C++
recursion, so that's a hard limit. (But: I don't know about the APIs
involved here, but at least some thread APIs let you specify the stack size
for newly created threads, so that might allow for customization.)
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
just with the points list:
a=[[0,0,0],[1,0,0],[1,0,0],[2,0,0],[2,2,0],[0,2,0]];
b=[[0,0,1],[0,0,1],[1,1,1],[2,1,1],[2,2,1],[0,2,1]];
c=[[0,1,1],[1,1,1],[1,1,1],[1,2,1],[0,2,1]];
d=[[0,1,2],[0,1,2],[1,2,2],[1,2,2],[0,2,2]];
s1=[a,b];
s2=[c,d];
color("blue") for(p=[s1,s2,cpo(s1),cpo(s2)]) for(p1=p) p_line3dc(p1,.02);
for(p=[s1,s2]) swp(p);
//module to draw a polyline in 3d space (loop closed)
module p_line3dc(path,d,rec=0,$fn=20){
for(i=[0:len(path)-1])
let(
i_plus=i<len(path)-1?i+1:0
)
hull(){
translate(path[i])if(rec==0)sphere(d/2); else cube(d,true);
translate(path[i_plus])if(rec==0)sphere(d/2);else cube(d,true);
}
}
function faces(sol)=
// calculate the faces for the vertices with shape l x m with first and
the last end closed
let(
l=len(sol),
m=len(sol[0]),
n1=[for(i=[0:m-1])i],
n2=[for(i=[0:l-2]) each ([ for(j=[0:m-1])
each
j<m-1?[[(j+1)+im,j+im,j+(i+1)m],[(j+1)+im,j+(i+1)m,(j+1)+(i+1)m]]:
[[0+im,j+im,j+(i+1)m],[0+im,j+(i+1)*m,0+(i+1)*m]]
])],
n3=[for(i=[0:m-1])i+(l-1)*m],
n4=[for(i=[len(n3)-1:-1:0])n3[i]],
n=[n1,each (n2),n4]
)n;
function vertices(sol)=
[each for (p=sol)p];
// module for rendering the polyhedron with ends closed
module swp(sol){
let(
v1=vertices(sol),
f1=faces(sol)
)
polyhedron(v1,f1,convexity=10);
}
//function to change the orientation of points of a prism.
function cpo(prism)=[for(i=[0:len(prism[0])-1])[for(p=prism)p[i]]];
[image: Screenshot 2026-01-23 at 6.39.23 AM.png]
On Wed, 21 Jan 2026 at 19:01, William F. Adams via Discuss <
discuss@lists.openscad.org> wrote:
This was recently put up on Reddit:
https://old.reddit.com/r/FreeCAD/comments/1qibk1y/fun_freecad_model_to_try_to_build/
I believe I got it in Block/OpenSCAD, ~20 minutes:
https://www.blockscad3d.com/community/projects/2052961
click on a "Create" button to make an STL to check (or see the attached
.scad file).
Is there a simpler/better way to make this?
Maybe using BOSL2?
William
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
There /must/ be an if() for tail recursion or it would never stop. Any
(and multiple) recursive call can be optimized from anywhere within a
function as long as the function immediately returns the results of the
call (in this case children) without doing anything with them.
module drawpt(p,max,count=0)
{
move(p) sphere(r=.01); /Tail elimination pseudo-code:/
dir=rand_int(1,3,1)[0];
if (count<max) if count < max
drawpt( dir==0 ? zrot(45,p) arg0 = (dir
== 0 ? ...)
: dir==1 ? xrot(45,p) arg1 =
max; arg2 = count + 1
: /*dir==2*/ yrot(45,p),max,count+1); goto top
without popping frame
} pop frame and
return children
I agree it would be very unusual to need it. More important is that
function() does implement tail recursion!
-Curt
On 1/22/26 16:07, Adrian Mariano via Discuss wrote:
The last statement in drawpt is an if() statement, not a recursion.
But I suspect that modules don't give special handling to tail
recursion, even if more generously interpreted. I think it's not
something that people normally try to do---thousands deep recursion in
a module. My application here is rather weird and there's probably a
better way to approach the problem of exploring the group generated by
45 deg rotations. I just took a quick/lazy one, figuring that if
there was some structure it might pop out. It could be rewritten as a
function that computes all the points. That would get tail recursion,
and then you could run arbitrarily many points. And you could check
how close the best match is to [1,1,1]. But for the picture, looping
drawpt() isn't an inferior choice, in terms of quality of the result.
On Thu, Jan 22, 2026 at 6:42 PM Curt McDowell via Discuss
discuss@lists.openscad.org wrote:
Evidently not, as drawpt is eligible for tail recursion as written.
On 1/22/26 15:15, Father Horton via Discuss wrote:
That's why I put a question mark. I don't know.
On Thu, Jan 22, 2026 at 4:54 PM Adrian Mariano <avm4@cornell.edu>
wrote:
Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton
<fatherhorton@gmail.com> wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss
<discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations
around the x, y and z axes?
An additional constraint: my probably-wrong
intuition says you should be able to do it with no
more than three rotations, zero or one in each of the
axes. (-45 rotations are OK.) That's a fairly small
number; maybe I'll put it together.
Note as an aside, is there no way to increase
allowed recursion depth? If I set the max much
higher it fails with "recursion detected" (like I
didn't know).
At least one of the limits, maybe the only limit, is
based on the compiled-in C++ stack size. OpenSCAD
recursion translates into C++ recursion, so that's a
hard limit. (But: I don't know about the APIs
involved here, but at least some thread APIs let you
specify the stack size for newly created threads, so
that might allow for customization.)
_______________________________________________
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
OpenSCAD mailing list
To unsubscribe send an email todiscuss-leave@lists.openscad.org
Jordan,
When we rotate [1, 0, 0] we could hope to arrive at [1, 1, 1] * √3 / 3
using only rotations of 45 degrees, But I don't believe it's possible.
Every matrix representing a rotation by 45 is in the Abelian matrix
field /M3 ℚ(√2//)/ because /sin(45) = cos(45) = //√2 / 2. S/o
regardless of how many multiplies, a coordinate could never occur that
is a multiple of √3.
Thanks for filing #6555 https://github.com/openscad/openscad/issues/6555!
-Curt
On 1/22/26 10:38, Jordan Brown via Discuss wrote:
On 1/22/2026 9:48 AM, Adrian Mariano via Discuss wrote:
Jordan, BOSL2 will help you avoid that trig and decrease the required
thinking as shown below. :)
Thanks, and I agree that's more obvious, but it's still unsatisfying
that it's not a sequence of 45° rotates. It probably can't be such
a sequence, but it should be.
On 1/22/2026 2:54 PM, Adrian Mariano wrote:
Do modules get special handling of tail recursion?
I forgot the distinction. I don't know, probably not.
OpenSCAD turns all your input into primitive shapes (circle, cylinder, polyhedron, etc), operations (union, intersection, and difference), and placement/resize (translate, rotate, scale, etc get turned into multmatrix). It doesn't try to be very smart about this and optimize (at this stage, at least); IIRC translate wrapping a translate results in two nested multmatrix operations, when that could obviously be one (if nothing was using the intermediate stage).
But notice I didn't list modules nor loops. Every module instantiation must result in the full tree of primitives, operations, and matrix operations because those are the only things the intermediate form can represent. It can't even do math; every value must be a literal number. It's simply impossible to write a subtree and reuse it. Thus it is impossible to have tail call elimination because you can't even represent calls!
On January 22, 2026 4:07:09 PM PST, Adrian Mariano via Discuss discuss@lists.openscad.org wrote:
The last statement in drawpt is an if() statement, not a recursion. But I
suspect that modules don't give special handling to tail recursion, even if
more generously interpreted. I think it's not something that people
normally try to do---thousands deep recursion in a module. My application
here is rather weird and there's probably a better way to approach the
problem of exploring the group generated by 45 deg rotations. I just took
a quick/lazy one, figuring that if there was some structure it might pop
out. It could be rewritten as a function that computes all the points.
That would get tail recursion, and then you could run arbitrarily many
points. And you could check how close the best match is to [1,1,1]. But
for the picture, looping drawpt() isn't an inferior choice, in terms of
quality of the result.
On Thu, Jan 22, 2026 at 6:42 PM Curt McDowell via Discuss <
discuss@lists.openscad.org> wrote:
Evidently not, as drawpt is eligible for tail recursion as written.
On 1/22/26 15:15, Father Horton via Discuss wrote:
That's why I put a question mark. I don't know.
On Thu, Jan 22, 2026 at 4:54 PM Adrian Mariano avm4@cornell.edu wrote:
Do modules get special handling of tail recursion?
On Thu, Jan 22, 2026 at 5:50 PM Father Horton fatherhorton@gmail.com
wrote:
Tail recursion?
On Thu, Jan 22, 2026 at 1:35 PM Jordan Brown via Discuss <
discuss@lists.openscad.org> wrote:
On 1/22/2026 11:25 AM, Adrian Mariano wrote:
The question: what can you get with 45 deg rotations around the x, y
and z axes?
An additional constraint: my probably-wrong intuition says you should
be able to do it with no more than three rotations, zero or one in each of
the axes. (-45 rotations are OK.) That's a fairly small number; maybe
I'll put it together.
Note as an aside, is there no way to increase allowed recursion depth?
If I set the max much higher it fails with "recursion detected" (like I
didn't know).
At least one of the limits, maybe the only limit, is based on the
compiled-in C++ stack size. OpenSCAD recursion translates into C++
recursion, so that's a hard limit. (But: I don't know about the APIs
involved here, but at least some thread APIs let you specify the stack size
for newly created threads, so that might allow for customization.)
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org