AM
Adrian Mariano
Sun, Aug 31, 2025 5:57 PM
Well, I guess you can talk about the case of expensive calculations that
are mostly never used, but it's not related to the question at hand.
Nathan said: "Is there a way to avoid recalculating a function a large
number of times? For example, if a function does nothing other than return
the sum of 2 other constant members, is there a way to assign a value to
the member that is a "calculated constant" instead of a function?"
He already knew how to use a function to compute it on demand, that is, by
just using a function directly, without a clunky access function.
Summing two numbers is not expensive to calculate, but really the key piece
of information is that the function is being recalculated a large number of
times. If the function is being recalculated a large number of times you
definitely want to compute it up front and not use a function literal for
it---and this is especially important if it's expensive to compute, because
without memoization, you're recomputing that expensive function each time.
I did try calculating the run time of function calls to see whether Nathan
is looking in the right place for his slow down. Building a matrix of 50
million copies of a constant took 6.9s and doing it using a function that
returned a constant took 16.4s. This seems to suggest that the overhead
for doing those function calls is 0.2 microseconds per call. You're going
to need a lot of function calls before this matters---on the order of
millions.
On Sun, Aug 31, 2025 at 11:50 AM Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:
I figured you would reply with the answer you did, so with the limited
information available, I thought I would cover the case where there are
many values to create, only a small subset will be used for any given
instance, and they are expensive to calculate.
If we're assuming this is the actual use, then side and angle should be
arrays :) and let or function args are the best.
On August 31, 2025 5:23:10 AM PDT, Adrian Mariano via Discuss <
discuss@lists.openscad.org> wrote:
Also the basic behavior of using a function is already "lazy evaluation".
That is, if you define a function member and access it as needed that's
calculated until you call it.
Yes, but I figured you would be giving the answer to calculate all fields
and assign as values into the object. So I offered the alternative where
the calculation is expensive but often unnecessary (though I didn't say
that).
And, of course, it's not actually lazy evaluation.
So I'd prefer
function ra(sideA, sideB) =
object(sides=[sideA,sideB,sqrt(sideA^2+sideB^2)], angles=[...]);
which form supports all polygons.
function to do this. You just need to know if your member is a function
not. But since memoization is impossible in a user-space lazy evaluation
scheme in OpenSCAD, it seems like applications for lazy evaluation are
limited and generally manageable by simply passing a function literal to
code that expects a function literal.
On Sat, Aug 30, 2025 at 10:15 PM Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:
I'm assuming you're trying to do lazy evaluation? My idea:
First, use Python convention of always having "self" as the first
of all functions intended as methods.
Second, don't retrieve values directly. Use this function:
function zed(obj, member) =
let ( thunk = obj[member] )
is_function(thunk) ? thunk(obj) : thunk;
member is a string unfortunately.
On August 30, 2025 4:19:58 PM PDT, Nathan Sokalski via Discuss <
discuss@lists.openscad.org> wrote:
How would I do something like the following?
righttriangle=object(
SideA=3,
SideB=4,
SideC=function()(sqrt((righttriangle.SideA^2)+(righttriangle.SideB^2))),
AngleA=function()(asin(righttriangle.SideA/righttriangle.SideC())),
AngleB=function()(asin(righttriangle.SideB/righttriangle.SideC())),
AngleC=90);
In this object, SideC, AngleA & AngleB will remain the same once the
object is created, but are unknown prior to calculation.
From: Adrian Mariano via Discuss discuss@lists.openscad.org
Sent: Saturday, August 30, 2025 5:48 PM
To: OpenSCAD general discussion Mailing-list <
discuss@lists.openscad.org>
Cc: Adrian Mariano avm4@cornell.edu
Subject: [OpenSCAD] Re: Functions as Object Members: Recalculation
slowing down compilation
If the function is going to return the same value after objection
creation shouldn't you be creating the object with that member as a
variable and compute its value at creation time?
On Sat, Aug 30, 2025 at 5:43 PM Nathan Sokalski via Discuss <
discuss@lists.openscad.org> wrote:
I have been working on a new model using the 2025.07.11 prebuild
containing the object() function. Many of my objects contain members
are functions, even functions that call other members that are also
functions. My code seems to be getting very slow, and (correct me if I
wrong) I was wondering if this is because so many functions are being
called so many times. Most of these function members will always
same value once the object is created (they do not have any
the equation or operations in them only use constants). Is there a way
avoid recalculating a function a large number of times? For example,
function does nothing other than return the sum of 2 other constant
members, is there a way to assign a value to the member that is a
"calculated constant" instead of a function?
Nathan Sokalski
njsokalski@hotmail.com
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org
Well, I guess you can talk about the case of expensive calculations that
are mostly never used, but it's not related to the question at hand.
Nathan said: "Is there a way to avoid recalculating a function a large
number of times? For example, if a function does nothing other than return
the sum of 2 other constant members, is there a way to assign a value to
the member that is a "calculated constant" instead of a function?"
He already knew how to use a function to compute it on demand, that is, by
just using a function directly, without a clunky access function.
Summing two numbers is not expensive to calculate, but really the key piece
of information is that the function is being recalculated a large number of
times. If the function is being recalculated a large number of times you
definitely want to compute it up front and not use a function literal for
it---and this is especially important if it's expensive to compute, because
without memoization, you're recomputing that expensive function each time.
I did try calculating the run time of function calls to see whether Nathan
is looking in the right place for his slow down. Building a matrix of 50
million copies of a constant took 6.9s and doing it using a function that
returned a constant took 16.4s. This seems to suggest that the overhead
for doing those function calls is 0.2 microseconds per call. You're going
to need a lot of function calls before this matters---on the order of
millions.
On Sun, Aug 31, 2025 at 11:50 AM Cory Cross via Discuss <
discuss@lists.openscad.org> wrote:
> I figured you would reply with the answer you did, so with the limited
> information available, I thought I would cover the case where there are
> many values to create, only a small subset will be used for any given
> instance, and they are expensive to calculate.
>
> If we're assuming this is the actual use, then side and angle should be
> arrays :) and let or function args are the best.
>
>
> On August 31, 2025 5:23:10 AM PDT, Adrian Mariano via Discuss <
> discuss@lists.openscad.org> wrote:
> >Also the basic behavior of using a function is already "lazy evaluation".
> >That is, if you define a function member and access it as needed that's
> not
> >calculated until you call it.
>
> Yes, but I figured you would be giving the answer to calculate all fields
> and assign as values into the object. So I offered the alternative where
> the calculation is expensive but often unnecessary (though I didn't say
> that).
>
> And, of course, it's not *actually* lazy evaluation.
>
> So I'd prefer
>
> function ra(sideA, sideB) =
> object(sides=[sideA,sideB,sqrt(sideA^2+sideB^2)], angles=[...]);
>
> which form supports all polygons.
>
> - Cory
>
> You don't need a special member access
> >function to do this. You just need to know if your member is a function
> or
> >not. But since memoization is impossible in a user-space lazy evaluation
> >scheme in OpenSCAD, it seems like applications for lazy evaluation are
> >limited and generally manageable by simply passing a function literal to
> >code that expects a function literal.
> >
> >On Sat, Aug 30, 2025 at 10:15 PM Cory Cross via Discuss <
> >discuss@lists.openscad.org> wrote:
> >
> >> I'm assuming you're trying to do lazy evaluation? My idea:
> >>
> >> First, use Python convention of always having "self" as the first
> argument
> >> of all functions intended as methods.
> >>
> >> Second, don't retrieve values directly. Use this function:
> >>
> >> function zed(obj, member) =
> >> let ( thunk = obj[member] )
> >> is_function(thunk) ? thunk(obj) : thunk;
> >>
> >> member is a string unfortunately.
> >>
> >>
> >>
> >> On August 30, 2025 4:19:58 PM PDT, Nathan Sokalski via Discuss <
> >> discuss@lists.openscad.org> wrote:
> >>
> >>> How would I do something like the following?
> >>> righttriangle=object(
> >>> SideA=3,
> >>> SideB=4,
> >>>
> SideC=function()(sqrt((righttriangle.SideA^2)+(righttriangle.SideB^2))),
> >>> AngleA=function()(asin(righttriangle.SideA/righttriangle.SideC())),
> >>> AngleB=function()(asin(righttriangle.SideB/righttriangle.SideC())),
> >>> AngleC=90);
> >>> In this object, SideC, AngleA & AngleB will remain the same once the
> >>> object is created, but are unknown prior to calculation.
> >>>
> >>> Nathan Sokalski
> >>> njsokalski@hotmail.com
> >>> ------------------------------
> >>> *From:* Adrian Mariano via Discuss <discuss@lists.openscad.org>
> >>> *Sent:* Saturday, August 30, 2025 5:48 PM
> >>> *To:* OpenSCAD general discussion Mailing-list <
> >>> discuss@lists.openscad.org>
> >>> *Cc:* Adrian Mariano <avm4@cornell.edu>
> >>> *Subject:* [OpenSCAD] Re: Functions as Object Members: Recalculation
> >>> slowing down compilation
> >>>
> >>> If the function is going to return the same value after objection
> >>> creation shouldn't you be creating the object with that member as a
> >>> variable and compute its value at creation time?
> >>>
> >>> On Sat, Aug 30, 2025 at 5:43 PM Nathan Sokalski via Discuss <
> >>> discuss@lists.openscad.org> wrote:
> >>>
> >>> I have been working on a new model using the 2025.07.11 prebuild
> >>> containing the object() function. Many of my objects contain members
> that
> >>> are functions, even functions that call other members that are also
> >>> functions. My code seems to be getting very slow, and (correct me if I
> am
> >>> wrong) I was wondering if this is because so many functions are being
> >>> called so many times. Most of these function members will always
> return the
> >>> same value once the object is created (they do not have any
> parameters, and
> >>> the equation or operations in them only use constants). Is there a way
> to
> >>> avoid recalculating a function a large number of times? For example,
> if a
> >>> function does nothing other than return the sum of 2 other constant
> >>> members, is there a way to assign a value to the member that is a
> >>> "calculated constant" instead of a function?
> >>>
> >>> Nathan Sokalski
> >>> njsokalski@hotmail.com
> >>> _______________________________________________
> >>> OpenSCAD mailing list
> >>> To unsubscribe send an email to discuss-leave@lists.openscad.org
> >>>
> >>> _______________________________________________
> >> OpenSCAD mailing list
> >> To unsubscribe send an email to discuss-leave@lists.openscad.org
> >>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org
PK
Peter Kriens
Tue, Sep 2, 2025 9:35 AM
Can you give me an example that gets slow?
Looking at the code I find it hard to see where the slowdown is except maybe for the function call code itself which was 25% of the profile. The object uses hashing so access cost should be negligible. It was so fast that I couldn't make it to show up in profiling the code.
I am curious how you access the other members? I have a stalled PR https://github.com/openscad/openscad/pull/6022 for this but in the current model a function inside an object has no access to its object?
So unless you use the PR build, your functions must still be referring to their original context?
Could you give an example?
Peter
On 30 Aug 2025, at 23:42, Nathan Sokalski via Discuss discuss@lists.openscad.org wrote:
I have been working on a new model using the 2025.07.11 prebuild containing the object() function. Many of my objects contain members that are functions, even functions that call other members that are also functions. My code seems to be getting very slow, and (correct me if I am wrong) I was wondering if this is because so many functions are being called so many times. Most of these function members will always return the same value once the object is created (they do not have any parameters, and the equation or operations in them only use constants). Is there a way to avoid recalculating a function a large number of times? For example, if a function does nothing other than return the sum of 2 other constant members, is there a way to assign a value to the member that is a "calculated constant" instead of a function?
Nathan Sokalski
njsokalski@hotmail.com mailto:njsokalski@hotmail.com
OpenSCAD mailing list
To unsubscribe send an email to discuss-leave@lists.openscad.org mailto:discuss-leave@lists.openscad.org
Can you give me an example that gets slow?
Looking at the code I find it hard to see where the slowdown is except maybe for the function call code itself which was 25% of the profile. The object uses hashing so access cost should be negligible. It was so fast that I couldn't make it to show up in profiling the code.
I am curious how you access the other members? I have a stalled PR <https://github.com/openscad/openscad/pull/6022> for this but in the current model a function inside an object has no access to its object?
So unless you use the PR build, your functions must still be referring to their original context?
Could you give an example?
Peter
> On 30 Aug 2025, at 23:42, Nathan Sokalski via Discuss <discuss@lists.openscad.org> wrote:
>
> I have been working on a new model using the 2025.07.11 prebuild containing the object() function. Many of my objects contain members that are functions, even functions that call other members that are also functions. My code seems to be getting very slow, and (correct me if I am wrong) I was wondering if this is because so many functions are being called so many times. Most of these function members will always return the same value once the object is created (they do not have any parameters, and the equation or operations in them only use constants). Is there a way to avoid recalculating a function a large number of times? For example, if a function does nothing other than return the sum of 2 other constant members, is there a way to assign a value to the member that is a "calculated constant" instead of a function?
>
> Nathan Sokalski
> njsokalski@hotmail.com <mailto:njsokalski@hotmail.com>
> _______________________________________________
> OpenSCAD mailing list
> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>