discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Re: New feature in 2025.07.11: the object() function

JB
Jon Bondy
Thu, Aug 21, 2025 9:56 PM

I have to agree with this.  If you call it an "object" then it should
conform to most people's intuitions about that facility. If you want to
create something that is very different than an object, that is fine;
just don't call it an object.

Jon

On 8/21/2025 5:18 PM, Cory Cross via Discuss wrote:

On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss discuss@lists.openscad.org wrote:

On 21 Aug 2025, at 01:55, Cory Cross via Discuss discuss@lists.openscad.org wrote:

Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy.

Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion.

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com

I have to agree with this.  If you call it an "object" then it should conform to most people's intuitions about that facility. If you want to create something that is very different than an object, that is fine; just don't call it an object. Jon On 8/21/2025 5:18 PM, Cory Cross via Discuss wrote: > On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org> wrote: >>> On 21 Aug 2025, at 01:55, Cory Cross via Discuss <discuss@lists.openscad.org> wrote: >> Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy. > Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion. > -- This email has been checked for viruses by AVG antivirus software. www.avg.com
LM
Leonard Martin Struttmann
Thu, Aug 21, 2025 11:28 PM

I very much agree with Jon's sentiment.  When I first heard that the new
things were going to be called "objects" I immediately, erroneously,
thought of Object Oriented programming.  I was relieved to learn we were
talking about the nearly equivalent of a Python dictionary.  Calling these
things "objects" will cause so much confusion.

Len

On Thu, Aug 21, 2025 at 4:56 PM Jon Bondy via Discuss <
discuss@lists.openscad.org> wrote:

I have to agree with this.  If you call it an "object" then it should
conform to most people's intuitions about that facility. If you want to
create something that is very different than an object, that is fine;
just don't call it an object.

Jon

On 8/21/2025 5:18 PM, Cory Cross via Discuss wrote:

On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <

On 21 Aug 2025, at 01:55, Cory Cross via Discuss <

Objects do NOT have parents so I am not sure what you're talking about?

An object is a flat set of key-value pairs. There is no hierarchy.

Then they shouldn't be called objects. At least 99% of people who have

or will use OpenSCAD will associate objects with the mainstream
object-oriented languages which all put inheritance front-and-center. It's
day-one "learning Python" material. I don't think there's a single language
with a "this" keyword that doesn't have inheritance. You're setting up
people for confusion.

--
This email has been checked for viruses by AVG antivirus software.
www.avg.com


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

I very much agree with Jon's sentiment. When I first heard that the new things were going to be called "objects" I immediately, erroneously, thought of Object Oriented programming. I was relieved to learn we were talking about the nearly equivalent of a Python dictionary. Calling these things "objects" will cause so much confusion. Len On Thu, Aug 21, 2025 at 4:56 PM Jon Bondy via Discuss < discuss@lists.openscad.org> wrote: > I have to agree with this. If you call it an "object" then it should > conform to most people's intuitions about that facility. If you want to > create something that is very different than an object, that is fine; > just don't call it an object. > > Jon > > On 8/21/2025 5:18 PM, Cory Cross via Discuss wrote: > > On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss < > discuss@lists.openscad.org> wrote: > >>> On 21 Aug 2025, at 01:55, Cory Cross via Discuss < > discuss@lists.openscad.org> wrote: > >> Objects do NOT have parents so I am not sure what you're talking about? > An object is a flat set of key-value pairs. There is no hierarchy. > > Then they shouldn't be called objects. At least 99% of people who have > or will use OpenSCAD will associate objects with the mainstream > object-oriented languages which all put inheritance front-and-center. It's > day-one "learning Python" material. I don't think there's a single language > with a "this" keyword that doesn't have inheritance. You're setting up > people for confusion. > > > > -- > This email has been checked for viruses by AVG antivirus software. > www.avg.com > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
FH
Father Horton
Thu, Aug 21, 2025 11:39 PM

FWIW, I also think that calling the new construct an “object” is more
confusing than helpful.

FWIW, I also think that calling the new construct an “object” is more confusing than helpful.
NS
Nathan Sokalski
Fri, Aug 22, 2025 12:16 AM

I agree that using the term object when certain attributes are missing/different could be confusing if someone is learning OpenSCAD for the first time, but I think it could also be confusing to try to use an unconventional or non-standard term. When learning a new language that is not based on one I have previously used (in other words, one with different key words), the hardest part for me is usually becoming familiar with the new key words. Even though this would still be OpenSCAD (not a completely new language), learning another key word rather than one that developers and other tech people that use OpenSCAD are familiar with is not worth it. The term object is intuitive enough that for a simple, not full-fledged scripting language it is worth the sacrifice of not meeting the technical definition of an object. OpenSCAD does not do complex communication with other languages, so it's OK to cut a few corners as long we understand it easily.

Nathan Sokalski
njsokalski@hotmail.commailto:njsokalski@hotmail.com


From: Father Horton via Discuss discuss@lists.openscad.org
Sent: Thursday, August 21, 2025 7:39 PM
To: OpenSCAD general discussion Mailing-list discuss@lists.openscad.org
Cc: Father Horton fatherhorton@gmail.com
Subject: [OpenSCAD] Re: Future of OO in OpenSCAD (was Re: Re: New feature in 2025.07.11: the object() function)

FWIW, I also think that calling the new construct an “object” is more confusing than helpful.

I agree that using the term object when certain attributes are missing/different could be confusing if someone is learning OpenSCAD for the first time, but I think it could also be confusing to try to use an unconventional or non-standard term. When learning a new language that is not based on one I have previously used (in other words, one with different key words), the hardest part for me is usually becoming familiar with the new key words. Even though this would still be OpenSCAD (not a completely new language), learning another key word rather than one that developers and other tech people that use OpenSCAD are familiar with is not worth it. The term object is intuitive enough that for a simple, not full-fledged scripting language it is worth the sacrifice of not meeting the technical definition of an object. OpenSCAD does not do complex communication with other languages, so it's OK to cut a few corners as long we understand it easily. Nathan Sokalski njsokalski@hotmail.com<mailto:njsokalski@hotmail.com> ________________________________ From: Father Horton via Discuss <discuss@lists.openscad.org> Sent: Thursday, August 21, 2025 7:39 PM To: OpenSCAD general discussion Mailing-list <discuss@lists.openscad.org> Cc: Father Horton <fatherhorton@gmail.com> Subject: [OpenSCAD] Re: Future of OO in OpenSCAD (was Re: Re: New feature in 2025.07.11: the object() function) FWIW, I also think that calling the new construct an “object” is more confusing than helpful.
HW
Harvey white
Fri, Aug 22, 2025 4:07 AM

You might consider calling the "this" a "thing" which may help with
understanding a bit.

Therefore instead of "this->" use "thing->"

Harvey

On 8/21/2025 7:39 PM, Father Horton via Discuss wrote:

FWIW, I also think that calling the new construct an “object” is more
confusing than helpful.


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

You might consider calling the "this" a "thing" which may help with understanding a bit. Therefore instead of "this->" use "thing->" Harvey On 8/21/2025 7:39 PM, Father Horton via Discuss wrote: > FWIW, I also think that calling the new construct an “object” is more > confusing than helpful. > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org
MK
Marius Kintel
Fri, Aug 22, 2025 1:20 PM

I guess nomenclature will always be confusing to some people depending on their background. I think about OpenSCAD objects in a similar way as I do JSON objects, POJOs, or even JavaScript objects. The surrounding runtime system may or may not use it for more than storing key-value pairs, but storing key-value pairs is still a core feature.

On Aug 22, 2025, at 00:07, Harvey white via Discuss discuss@lists.openscad.org wrote:

You might consider calling the "this" a "thing" which may help with understanding a bit.

Therefore instead of "this->" use "thing->"

Harvey

On 8/21/2025 7:39 PM, Father Horton via Discuss wrote:
FWIW, I also think that calling the new construct an “object” is more confusing than helpful.


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

I guess nomenclature will always be confusing to some people depending on their background. I think about OpenSCAD objects in a similar way as I do JSON objects, POJOs, or even JavaScript objects. The surrounding runtime system may or may not use it for more than storing key-value pairs, but storing key-value pairs is still a core feature. > On Aug 22, 2025, at 00:07, Harvey white via Discuss <discuss@lists.openscad.org> wrote: > > You might consider calling the "this" a "thing" which may help with understanding a bit. > > Therefore instead of "this->" use "thing->" > > Harvey > > >> On 8/21/2025 7:39 PM, Father Horton via Discuss wrote: >> FWIW, I also think that calling the new construct an “object” is more confusing than helpful. >> >> _______________________________________________ >> 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
Fri, Aug 22, 2025 2:14 PM

This discussion is imho a perfect example of bikeshedding https://en.wiktionary.org/wiki/bikeshedding. We can discuss this forever on a forum like this because we're all highly experienced & opinionated but in the mean time OpenSCAD has no KV pairs ... The enemy of good is 'better' ... This is exactly how the OEP8 effort got derailed more than 2 years ago. At a certain moment everybody gets confused and it dies.

I suggest you make a working PR so we can play with concrete proposals instead of trying to infer what your sketches mean. If I can use KV pairs and get some concise way to make methods I happily close my PR and support yours.

I personally would appreciate a time box so we can make sure this does not get delayed another two years again.

Peter

On 21 Aug 2025, at 23:18, Cory Cross via Discuss discuss@lists.openscad.org wrote:

On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:

On 21 Aug 2025, at 01:55, Cory Cross via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:

Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy.

Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion.

We are very intentionally not implementing a full blow OO system to keep OpenSCAD as simple as possible, but not simpler.

Following this logic, not adding it is simpler.

What do you want to be simple: writing SCAD or the implementation of OpenSCAD? There's often (but not always) a trade-off. Brainfuck is very simple to implement. You can solve some very complicated analyses in a single line of Mathematica.

So we already have the power to do builders, it's just slightly uglier and slower. My question is while settle for "this" when generic functions are even nicer?

Slightly??? We must live in another universe. There are few types of code I'd like to write less than this kind of boiler plate code. I wrote several of these 'OO' systems but they were quite ugly.

"this" refers to the proposal to add a "this" keyword. But what I wrote shows that, with a couple helper functions, the proposed object() does not result in substantially simpler code and by the maxim "keep OpenSCAD as simple as possible, but not simpler", shouldn't be added.

Then you threw in an a-bom ... and another one. I am getting a bit desperate and feel this is going way off the track and taking way too much of my time ...

I am new here so I might not understand the mores in this project.

I am new as well (though a user for many years).

However, in other projects I am used that if you want to derail a PR you make a fully working counter PR so people can play with the proposals and compare. I find that you're now just dropping disruptive ideas ...

I've not found any other discussion of OEP8 and wasn't active at the time anyway. I am discussing now because now is when I'm here.

It's my impression the "this" keyword is just being added because people are unfamiliar with other systems. If SCAD was a hybrid procedural/OO lisp with mutable values like JavaScript, then it'd be fine to copy their semantics. But it's not and I think you're going down the wrong road.

I'm trying to prove it by picking bosl2 and showing how I'd refactor it using the proposed "this" approach or the one I'm proposing, because ultimately what we want is what makes it easier and faster to write correct code, right?

Everything I've proposed is quite easy to implement and I'll be happy to do it and/or collaborate on it.

The danger here is that we spend a lot of time talking back and forth and then nothing happens again because everything got so complicated. I think this partly happened with OEP8 and that spent a lot of time in discussion. There are very good, some crucial, ideas in that PR that has been idling since 2023.

I also think it's important to keep momentum up.

I know I can be a bit blunt but you can blame it on my Dutch citizenship ;-)

I can be a bit blunt but you can blame it on my Dutch ancestry :-).

  • Cory Cross
Peter

Actually, plists are better because you can get super methods :-)

I'm on my phone composing this without Internet access, so please forgive the formatting and mild syntax errors.

On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss discuss@lists.openscad.org wrote:

You flabbergasted me with the completely different direction/syntax you took but then at the end I saw that you came to the conclusion you could do all this also with 'this' and object? Not good for my blood pressure! :-)

I like the builder approach and it is one of my drivers for the object work and $this.

BTW, notice that OEP8 also proposed to have modules as expression. I am currently working on a PR for this. This will allow builders to also call modules, have modules as variables, and hopefully modules as methods when we can finally close [the $]this discussion ...

Peter Kriens

On 19 Aug 2025, at 07:47, Cory Cross via Discuss discuss@lists.openscad.org wrote:
On 8/16/25 8:49 AM, Jordan Brown wrote:

bosl2::threading::nut_builder::new(required, args, here)->optional_generic_arg(its_value)->reify();

I'm very sympathetic to the desire to reduce repetition in argument handling, but I'm not understanding what that means at all.  Partly that's presentation; is this intended to be how the library would say something, or how the caller would invoke the function?
If the former, I don't understand what it means.  If the latter, are you seriously suggesting this as a replacement for
threaded_nut(required, args, here, optional_generic_arc=its_value);

I am suggesting it as a replacement for the latter; not because it's better for the user, but because it's better for the maintainers and not worse for the users. (I would assume we'd add using bosl2::threading to shorten names, at some point).

As a practical example, here is a invocation of a threaded module in my code:

buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK);

here's how I would do it with the builder pattern and the suggested OO approach:

buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify;

You don't have to use the builder pattern. You could choose to use objects as a replacement for Python's **kwargs:

buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK));

In this case, buttress_threaded_nut's implementation would change from 50 lines to 11:

module buttress_threaded_nut(kwargs) {
profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
];
generic_threaded_nut(struct(kwargs, profile=profile));
}

Of course, this isn't OO and makes it harder to detect argument name typos and such.

The builder pattern could be implemented as so:

// namespace for buttress_threaded_nut_builder
obj = struct(generic_threaded_nut_builder::new());
function new() =
let ( profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
])
struct(obj)->profile(profile);

so not any more or less difficult to write. What do profile and positioning look like?

// namespace of generic_threaded_rod_builder
function profile(o is builder_obj, profile) =
assert(is_list(profile)) // And other tests independent of other values
struct(o,profile=profile);

// namespace of attachable_builder
function positioning(o is attachable_builder_obj, anchor, spin, orient) =
assert(/* tests related to the parameters*/)
let(
l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
is_undef(spin) ? [] : [["spin", spin]],
is_undef(orient) ? [] : [["orient", orient]])
)
struct(o,l);

Okay, not in love with the repetition in there. But there are some improvements here:

  1. Some validation can now stop cluttering the top of so many functions/modules.
  2. The get_radius function doesn't need its args filled out every time
  3. We're reusing attachable instead of needing to redundantly pass it so many args every single time and in every function and module signature.
  4. We can match on the old types and convert to objects as needed

Unsolved issue: why would -> method invocation not look at the namespace of positioning? I didn't intend it to, but it would do the wrong thing as written; only the calls in the new() methods should add the namespace to the method lookup. This might be best as object vs struct keywords.
Maybe attachable should be a mixin instead of in the class hierarchy.

So how would I write this with this as currently proposed?

function buttress_threaded_nut_builder =
let ( profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
])
object(new_generic_threaded_rod_builder().set_profile(profile), /* all methods on buttress_threaded_nut_builder must be defined here */);

// in method list of generic_threaded_rod_builder
function set_profile(profile) =
assert(is_list(profile)) // And other tests independent of other values
object(this,profile=profile);

// in method list of attachable_builder
function set_positioning(anchor, spin, orient) =
assert(/* tests related to the parameters*/)
let(
l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
is_undef(spin) ? [] : [["spin", spin]],
is_undef(orient) ? [] : [["orient", orient]])
)
struct(this,l);

module reify_buttress_threaded_nut(obj) {
reify_threaded_nut(obj);
}

module reify_threaded_nut(obj) {
reify_generic_threaded_nut(obj);
}

reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK));

...

Less different than I thought. Cascading explicit reify modules are annoying. For this usage the inability to write your own generic methods dispatching on other object types does not hinder anything. The shared namespace means methods and values must have unique names. I think this is supposed to solve name conflicts by having you only need one unique name per file and you put all your constants in there? And methods, I guess, so at the top of f.ex. bosl2/threading.scad there would be:

bosl2_threading = object(
top_level_constant = 27,
function buttress_threaded_nut_builder() =
...
);

module reify_buttress_threaded_nut(obj) {
bosl2_threading.top_level_constant; // for whatever reason
reify_threaded_nut(obj);
}

I've seen worse. I certainly can't say this rules out this.


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


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


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

This discussion is imho a perfect example of bikeshedding <https://en.wiktionary.org/wiki/bikeshedding>. We can discuss this forever on a forum like this because we're all highly experienced & opinionated but in the mean time OpenSCAD has no KV pairs ... The enemy of good is 'better' ... This is exactly how the OEP8 effort got derailed more than 2 years ago. At a certain moment everybody gets confused and it dies. I suggest you make a working PR so we can play with concrete proposals instead of trying to infer what your sketches mean. If I can use KV pairs and get some concise way to make methods I happily close my PR and support yours. I personally would appreciate a time box so we can make sure this does not get delayed another two years again. Peter > On 21 Aug 2025, at 23:18, Cory Cross via Discuss <discuss@lists.openscad.org> wrote: > > > > On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >>> On 21 Aug 2025, at 01:55, Cory Cross via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >> Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy. > > Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion. > >> We are very intentionally not implementing a full blow OO system to keep OpenSCAD as simple as possible, but not simpler. > > Following this logic, not adding it is simpler. > > What do you want to be simple: writing SCAD or the implementation of OpenSCAD? There's often (but not always) a trade-off. Brainfuck is very simple to implement. You can solve some very complicated analyses in a single line of Mathematica. > >>> So we already have the power to do builders, it's just slightly uglier and slower. My question is while settle for "this" when generic functions are even nicer? >> >> Slightly??? We must live in another universe. There are few types of code I'd like to write less than this kind of boiler plate code. I wrote several of these 'OO' systems but they were quite ugly. > > "this" refers to the proposal to add a "this" keyword. But what I wrote shows that, with a couple helper functions, the proposed object() does not result in substantially simpler code and by the maxim "keep OpenSCAD as simple as possible, but not simpler", shouldn't be added. > >> Then you threw in an a-bom ... and another one. I am getting a bit desperate and feel this is going way off the track and taking way too much of my time ... >> >> I am new here so I might not understand the mores in this project. > > I am new as well (though a user for many years). > >> However, in other projects I am used that if you want to derail a PR you make a fully working counter PR so people can play with the proposals and compare. I find that you're now just dropping disruptive ideas ... > > I've not found any other discussion of OEP8 and wasn't active at the time anyway. I am discussing now because now is when I'm here. > > It's my impression the "this" keyword is just being added because people are unfamiliar with other systems. If SCAD was a hybrid procedural/OO lisp with mutable values like JavaScript, then it'd be fine to copy their semantics. But it's not and I think you're going down the wrong road. > > I'm trying to prove it by picking bosl2 and showing how I'd refactor it using the proposed "this" approach or the one I'm proposing, because ultimately what we want is what makes it easier and faster to write correct code, right? > > Everything I've proposed is quite easy to implement and I'll be happy to do it and/or collaborate on it. > >> The danger here is that we spend a lot of time talking back and forth and then nothing happens again because everything got so complicated. I think this partly happened with OEP8 and that spent a lot of time in discussion. There are very good, some crucial, ideas in that PR that has been idling since 2023. > > I also think it's important to keep momentum up. > >> I know I can be a bit blunt but you can blame it on my Dutch citizenship ;-) > > I can be a bit blunt but you can blame it on my Dutch ancestry :-). > > - Cory Cross > >> >> Peter >> >> >> >>> >>> Actually, plists are better because you can get super methods :-) >>> >>> >>> I'm on my phone composing this without Internet access, so please forgive the formatting and mild syntax errors. >>> >>> >>> >>> On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org> wrote: >>>> You flabbergasted me with the completely different direction/syntax you took but then at the end I saw that you came to the conclusion you could do all this also with 'this' and `object`? Not good for my blood pressure! :-) >>>> >>>> I like the builder approach and it is one of my drivers for the object work and $this. >>>> >>>> BTW, notice that OEP8 also proposed to have modules as expression. I am currently working on a PR for this. This will allow builders to also call modules, have modules as variables, and hopefully modules as methods when we can finally close [the $]this discussion ... >>>> >>>> Peter Kriens >>>> >>>>> On 19 Aug 2025, at 07:47, Cory Cross via Discuss <discuss@lists.openscad.org> wrote: >>>>> On 8/16/25 8:49 AM, Jordan Brown wrote: >>>>>>> bosl2::threading::nut_builder::new(required, args, here)->optional_generic_arg(its_value)->reify(); >>>>>> I'm very sympathetic to the desire to reduce repetition in argument handling, but I'm not understanding what that means at all. Partly that's presentation; is this intended to be how the library would say something, or how the caller would invoke the function? >>>>>> If the former, I don't understand what it means. If the latter, are you seriously suggesting this as a replacement for >>>>>> threaded_nut(required, args, here, optional_generic_arc=its_value); >>>>> I am suggesting it as a replacement for the latter; not because it's better for the user, but because it's better for the maintainers and not worse for the users. (I would assume we'd add `using bosl2::threading` to shorten names, at some point). >>>>> >>>>> As a practical example, here is a invocation of a threaded module in my code: >>>>> >>>>> buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK); >>>>> >>>>> here's how I would do it with the builder pattern and the suggested OO approach: >>>>> >>>>> buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify; >>>>> >>>>> You don't have to use the builder pattern. You could choose to use objects as a replacement for Python's **kwargs: >>>>> >>>>> buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK)); >>>>> >>>>> In this case, buttress_threaded_nut's implementation would change from 50 lines to 11: >>>>> >>>>> module buttress_threaded_nut(kwargs) { >>>>> profile = [ >>>>> [ -1/2, -0.77], >>>>> [ -7/16, -0.75], >>>>> [ 5/16, 0], >>>>> [ 7/16, 0], >>>>> [ 7/16, -0.75], >>>>> [ 1/ 2, -0.77], >>>>> ]; >>>>> generic_threaded_nut(struct(kwargs, profile=profile)); >>>>> } >>>>> >>>>> Of course, this isn't OO and makes it harder to detect argument name typos and such. >>>>> >>>>> The builder pattern could be implemented as so: >>>>> >>>>> // namespace for buttress_threaded_nut_builder >>>>> obj = struct(generic_threaded_nut_builder::new()); >>>>> function new() = >>>>> let ( profile = [ >>>>> [ -1/2, -0.77], >>>>> [ -7/16, -0.75], >>>>> [ 5/16, 0], >>>>> [ 7/16, 0], >>>>> [ 7/16, -0.75], >>>>> [ 1/ 2, -0.77], >>>>> ]) >>>>> struct(obj)->profile(profile); >>>>> >>>>> so not any more or less difficult to write. What do profile and positioning look like? >>>>> >>>>> // namespace of generic_threaded_rod_builder >>>>> function profile(o is builder_obj, profile) = >>>>> assert(is_list(profile)) // And other tests independent of other values >>>>> struct(o,profile=profile); >>>>> >>>>> // namespace of attachable_builder >>>>> function positioning(o is attachable_builder_obj, anchor, spin, orient) = >>>>> assert(/* tests related to the parameters*/) >>>>> let( >>>>> l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>> is_undef(spin) ? [] : [["spin", spin]], >>>>> is_undef(orient) ? [] : [["orient", orient]]) >>>>> ) >>>>> struct(o,l); >>>>> >>>>> Okay, not in love with the repetition in there. But there are some improvements here: >>>>> >>>>> 1. Some validation can now stop cluttering the top of so many functions/modules. >>>>> 2. The `get_radius` function doesn't need its args filled out every time >>>>> 3. We're reusing attachable instead of needing to redundantly pass it so many args every single time and in every function and module signature. >>>>> 4. We can match on the old types and convert to objects as needed >>>>> >>>>> Unsolved issue: why would -> method invocation not look at the namespace of positioning? I didn't intend it to, but it would do the wrong thing as written; only the calls in the new() methods should add the namespace to the method lookup. This might be best as `object` vs `struct` keywords. >>>>> Maybe attachable should be a mixin instead of in the class hierarchy. >>>>> >>>>> So how would I write this with `this` as currently proposed? >>>>> >>>>> function buttress_threaded_nut_builder = >>>>> let ( profile = [ >>>>> [ -1/2, -0.77], >>>>> [ -7/16, -0.75], >>>>> [ 5/16, 0], >>>>> [ 7/16, 0], >>>>> [ 7/16, -0.75], >>>>> [ 1/ 2, -0.77], >>>>> ]) >>>>> object(new_generic_threaded_rod_builder().set_profile(profile), /* all methods on buttress_threaded_nut_builder must be defined here */); >>>>> >>>>> // in method list of generic_threaded_rod_builder >>>>> function set_profile(profile) = >>>>> assert(is_list(profile)) // And other tests independent of other values >>>>> object(this,profile=profile); >>>>> >>>>> // in method list of attachable_builder >>>>> function set_positioning(anchor, spin, orient) = >>>>> assert(/* tests related to the parameters*/) >>>>> let( >>>>> l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>> is_undef(spin) ? [] : [["spin", spin]], >>>>> is_undef(orient) ? [] : [["orient", orient]]) >>>>> ) >>>>> struct(this,l); >>>>> >>>>> module reify_buttress_threaded_nut(obj) { >>>>> reify_threaded_nut(obj); >>>>> } >>>>> >>>>> >>>>> module reify_threaded_nut(obj) { >>>>> reify_generic_threaded_nut(obj); >>>>> } >>>>> >>>>> reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK)); >>>>> >>>>> >>>>> ... >>>>> >>>>> Less different than I thought. Cascading explicit reify modules are annoying. For this usage the inability to write your own generic methods dispatching on other object types does not hinder anything. The shared namespace means methods and values must have unique names. I think this is supposed to solve name conflicts by having you only need one unique name per file and you put all your constants in there? And methods, I guess, so at the top of f.ex. bosl2/threading.scad there would be: >>>>> >>>>> bosl2_threading = object( >>>>> top_level_constant = 27, >>>>> function buttress_threaded_nut_builder() = >>>>> ... >>>>> ); >>>>> >>>>> module reify_buttress_threaded_nut(obj) { >>>>> bosl2_threading.top_level_constant; // for whatever reason >>>>> reify_threaded_nut(obj); >>>>> } >>>>> >>>>> I've seen worse. I certainly can't say this rules out `this`. >>>>> _______________________________________________ >>>>> 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 >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org> > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
CC
Cory Cross
Fri, Aug 22, 2025 4:05 PM

On August 22, 2025 10:14:28 AM EDT, Peter Kriens via Discuss discuss@lists.openscad.org wrote:

This discussion is imho a perfect example of bikeshedding https://en.wiktionary.org/wiki/bikeshedding. We can discuss this forever on a forum like this because we're all highly experienced & opinionated but in the mean time OpenSCAD has no KV pairs

Let's stop trying to make them objects and just call them dictionary, map, associative array, or any of the many other names for this: https://en.m.wikipedia.org/wiki/Associative_array

The words you use carry connotations and have denotations that users will use to understand what it is. If you offer to pay 100 Euros and show up with a 1-Euro bill, the other party is going to be upset and confused even if you explain you don't pronounce the "ents" of "cents".

  • Cory

I personally would appreciate a time box so we can make sure this does not get delayed another two years again.

Peter

On 21 Aug 2025, at 23:18, Cory Cross via Discuss discuss@lists.openscad.org wrote:

On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:

On 21 Aug 2025, at 01:55, Cory Cross via Discuss <discuss@lists.openscad.org mailto:discuss@lists.openscad.org> wrote:
Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy.

Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion.

We are very intentionally not implementing a full blow OO system to keep OpenSCAD as simple as possible, but not simpler.

Following this logic, not adding it is simpler.

What do you want to be simple: writing SCAD or the implementation of OpenSCAD? There's often (but not always) a trade-off. Brainfuck is very simple to implement. You can solve some very complicated analyses in a single line of Mathematica.

So we already have the power to do builders, it's just slightly uglier and slower. My question is while settle for "this" when generic functions are even nicer?

Slightly??? We must live in another universe. There are few types of code I'd like to write less than this kind of boiler plate code. I wrote several of these 'OO' systems but they were quite ugly.

"this" refers to the proposal to add a "this" keyword. But what I wrote shows that, with a couple helper functions, the proposed object() does not result in substantially simpler code and by the maxim "keep OpenSCAD as simple as possible, but not simpler", shouldn't be added.

Then you threw in an a-bom ... and another one. I am getting a bit desperate and feel this is going way off the track and taking way too much of my time ...

I am new here so I might not understand the mores in this project.

I am new as well (though a user for many years).

However, in other projects I am used that if you want to derail a PR you make a fully working counter PR so people can play with the proposals and compare. I find that you're now just dropping disruptive ideas ...

I've not found any other discussion of OEP8 and wasn't active at the time anyway. I am discussing now because now is when I'm here.

It's my impression the "this" keyword is just being added because people are unfamiliar with other systems. If SCAD was a hybrid procedural/OO lisp with mutable values like JavaScript, then it'd be fine to copy their semantics. But it's not and I think you're going down the wrong road.

I'm trying to prove it by picking bosl2 and showing how I'd refactor it using the proposed "this" approach or the one I'm proposing, because ultimately what we want is what makes it easier and faster to write correct code, right?

Everything I've proposed is quite easy to implement and I'll be happy to do it and/or collaborate on it.

The danger here is that we spend a lot of time talking back and forth and then nothing happens again because everything got so complicated. I think this partly happened with OEP8 and that spent a lot of time in discussion. There are very good, some crucial, ideas in that PR that has been idling since 2023.

I also think it's important to keep momentum up.

I know I can be a bit blunt but you can blame it on my Dutch citizenship ;-)

I can be a bit blunt but you can blame it on my Dutch ancestry :-).

  • Cory Cross

Peter

Actually, plists are better because you can get super methods :-)

I'm on my phone composing this without Internet access, so please forgive the formatting and mild syntax errors.

On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss discuss@lists.openscad.org wrote:

You flabbergasted me with the completely different direction/syntax you took but then at the end I saw that you came to the conclusion you could do all this also with 'this' and object? Not good for my blood pressure! :-)

I like the builder approach and it is one of my drivers for the object work and $this.

BTW, notice that OEP8 also proposed to have modules as expression. I am currently working on a PR for this. This will allow builders to also call modules, have modules as variables, and hopefully modules as methods when we can finally close [the $]this discussion ...

Peter Kriens

On 19 Aug 2025, at 07:47, Cory Cross via Discuss discuss@lists.openscad.org wrote:
On 8/16/25 8:49 AM, Jordan Brown wrote:

bosl2::threading::nut_builder::new(required, args, here)->optional_generic_arg(its_value)->reify();
I'm very sympathetic to the desire to reduce repetition in argument handling, but I'm not understanding what that means at all.  Partly that's presentation; is this intended to be how the library would say something, or how the caller would invoke the function?
If the former, I don't understand what it means.  If the latter, are you seriously suggesting this as a replacement for
threaded_nut(required, args, here, optional_generic_arc=its_value);
I am suggesting it as a replacement for the latter; not because it's better for the user, but because it's better for the maintainers and not worse for the users. (I would assume we'd add using bosl2::threading to shorten names, at some point).

As a practical example, here is a invocation of a threaded module in my code:

buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK);

here's how I would do it with the builder pattern and the suggested OO approach:

buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify;

You don't have to use the builder pattern. You could choose to use objects as a replacement for Python's **kwargs:

buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK));

In this case, buttress_threaded_nut's implementation would change from 50 lines to 11:

module buttress_threaded_nut(kwargs) {
profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
];
generic_threaded_nut(struct(kwargs, profile=profile));
}

Of course, this isn't OO and makes it harder to detect argument name typos and such.

The builder pattern could be implemented as so:

// namespace for buttress_threaded_nut_builder
obj = struct(generic_threaded_nut_builder::new());
function new() =
let ( profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
])
struct(obj)->profile(profile);

so not any more or less difficult to write. What do profile and positioning look like?

// namespace of generic_threaded_rod_builder
function profile(o is builder_obj, profile) =
assert(is_list(profile)) // And other tests independent of other values
struct(o,profile=profile);

// namespace of attachable_builder
function positioning(o is attachable_builder_obj, anchor, spin, orient) =
assert(/* tests related to the parameters*/)
let(
l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
is_undef(spin) ? [] : [["spin", spin]],
is_undef(orient) ? [] : [["orient", orient]])
)
struct(o,l);

Okay, not in love with the repetition in there. But there are some improvements here:

  1. Some validation can now stop cluttering the top of so many functions/modules.
  2. The get_radius function doesn't need its args filled out every time
  3. We're reusing attachable instead of needing to redundantly pass it so many args every single time and in every function and module signature.
  4. We can match on the old types and convert to objects as needed

Unsolved issue: why would -> method invocation not look at the namespace of positioning? I didn't intend it to, but it would do the wrong thing as written; only the calls in the new() methods should add the namespace to the method lookup. This might be best as object vs struct keywords.
Maybe attachable should be a mixin instead of in the class hierarchy.

So how would I write this with this as currently proposed?

function buttress_threaded_nut_builder =
let ( profile = [
[  -1/2, -0.77],
[ -7/16, -0.75],
[  5/16,  0],
[  7/16,  0],
[  7/16, -0.75],
[  1/ 2, -0.77],
])
object(new_generic_threaded_rod_builder().set_profile(profile), /* all methods on buttress_threaded_nut_builder must be defined here */);

// in method list of generic_threaded_rod_builder
function set_profile(profile) =
assert(is_list(profile)) // And other tests independent of other values
object(this,profile=profile);

// in method list of attachable_builder
function set_positioning(anchor, spin, orient) =
assert(/* tests related to the parameters*/)
let(
l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
is_undef(spin) ? [] : [["spin", spin]],
is_undef(orient) ? [] : [["orient", orient]])
)
struct(this,l);

module reify_buttress_threaded_nut(obj) {
reify_threaded_nut(obj);
}

module reify_threaded_nut(obj) {
reify_generic_threaded_nut(obj);
}

reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK));

...

Less different than I thought. Cascading explicit reify modules are annoying. For this usage the inability to write your own generic methods dispatching on other object types does not hinder anything. The shared namespace means methods and values must have unique names. I think this is supposed to solve name conflicts by having you only need one unique name per file and you put all your constants in there? And methods, I guess, so at the top of f.ex. bosl2/threading.scad there would be:

bosl2_threading = object(
top_level_constant = 27,
function buttress_threaded_nut_builder() =
...
);

module reify_buttress_threaded_nut(obj) {
bosl2_threading.top_level_constant; // for whatever reason
reify_threaded_nut(obj);
}

I've seen worse. I certainly can't say this rules out this.


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


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


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

On August 22, 2025 10:14:28 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org> wrote: >This discussion is imho a perfect example of bikeshedding <https://en.wiktionary.org/wiki/bikeshedding>. We can discuss this forever on a forum like this because we're all highly experienced & opinionated but in the mean time OpenSCAD has no KV pairs Let's stop trying to make them objects and just call them dictionary, map, associative array, or any of the many other names for this: https://en.m.wikipedia.org/wiki/Associative_array The words you use carry connotations and have denotations that users will use to understand what it is. If you offer to pay 100 Euros and show up with a 1-Euro bill, the other party is going to be upset and confused even if you explain you don't pronounce the "ents" of "cents". - Cory >I personally would appreciate a time box so we can make sure this does not get delayed another two years again. > > Peter > > >> On 21 Aug 2025, at 23:18, Cory Cross via Discuss <discuss@lists.openscad.org> wrote: >> >> >> >> On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >>>> On 21 Aug 2025, at 01:55, Cory Cross via Discuss <discuss@lists.openscad.org <mailto:discuss@lists.openscad.org>> wrote: >>> Objects do NOT have parents so I am not sure what you're talking about? An object is a flat set of key-value pairs. There is no hierarchy. >> >> Then they shouldn't be called objects. At least 99% of people who have or will use OpenSCAD will associate objects with the mainstream object-oriented languages which all put inheritance front-and-center. It's day-one "learning Python" material. I don't think there's a single language with a "this" keyword that doesn't have inheritance. You're setting up people for confusion. >> >>> We are very intentionally not implementing a full blow OO system to keep OpenSCAD as simple as possible, but not simpler. >> >> Following this logic, not adding it is simpler. >> >> What do you want to be simple: writing SCAD or the implementation of OpenSCAD? There's often (but not always) a trade-off. Brainfuck is very simple to implement. You can solve some very complicated analyses in a single line of Mathematica. >> >>>> So we already have the power to do builders, it's just slightly uglier and slower. My question is while settle for "this" when generic functions are even nicer? >>> >>> Slightly??? We must live in another universe. There are few types of code I'd like to write less than this kind of boiler plate code. I wrote several of these 'OO' systems but they were quite ugly. >> >> "this" refers to the proposal to add a "this" keyword. But what I wrote shows that, with a couple helper functions, the proposed object() does not result in substantially simpler code and by the maxim "keep OpenSCAD as simple as possible, but not simpler", shouldn't be added. >> >>> Then you threw in an a-bom ... and another one. I am getting a bit desperate and feel this is going way off the track and taking way too much of my time ... >>> >>> I am new here so I might not understand the mores in this project. >> >> I am new as well (though a user for many years). >> >>> However, in other projects I am used that if you want to derail a PR you make a fully working counter PR so people can play with the proposals and compare. I find that you're now just dropping disruptive ideas ... >> >> I've not found any other discussion of OEP8 and wasn't active at the time anyway. I am discussing now because now is when I'm here. >> >> It's my impression the "this" keyword is just being added because people are unfamiliar with other systems. If SCAD was a hybrid procedural/OO lisp with mutable values like JavaScript, then it'd be fine to copy their semantics. But it's not and I think you're going down the wrong road. >> >> I'm trying to prove it by picking bosl2 and showing how I'd refactor it using the proposed "this" approach or the one I'm proposing, because ultimately what we want is what makes it easier and faster to write correct code, right? >> >> Everything I've proposed is quite easy to implement and I'll be happy to do it and/or collaborate on it. >> >>> The danger here is that we spend a lot of time talking back and forth and then nothing happens again because everything got so complicated. I think this partly happened with OEP8 and that spent a lot of time in discussion. There are very good, some crucial, ideas in that PR that has been idling since 2023. >> >> I also think it's important to keep momentum up. >> >>> I know I can be a bit blunt but you can blame it on my Dutch citizenship ;-) >> >> I can be a bit blunt but you can blame it on my Dutch ancestry :-). >> >> - Cory Cross >> >>> >>> Peter >>> >>> >>> >>>> >>>> Actually, plists are better because you can get super methods :-) >>>> >>>> >>>> I'm on my phone composing this without Internet access, so please forgive the formatting and mild syntax errors. >>>> >>>> >>>> >>>> On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss <discuss@lists.openscad.org> wrote: >>>>> You flabbergasted me with the completely different direction/syntax you took but then at the end I saw that you came to the conclusion you could do all this also with 'this' and `object`? Not good for my blood pressure! :-) >>>>> >>>>> I like the builder approach and it is one of my drivers for the object work and $this. >>>>> >>>>> BTW, notice that OEP8 also proposed to have modules as expression. I am currently working on a PR for this. This will allow builders to also call modules, have modules as variables, and hopefully modules as methods when we can finally close [the $]this discussion ... >>>>> >>>>> Peter Kriens >>>>> >>>>>> On 19 Aug 2025, at 07:47, Cory Cross via Discuss <discuss@lists.openscad.org> wrote: >>>>>> On 8/16/25 8:49 AM, Jordan Brown wrote: >>>>>>>> bosl2::threading::nut_builder::new(required, args, here)->optional_generic_arg(its_value)->reify(); >>>>>>> I'm very sympathetic to the desire to reduce repetition in argument handling, but I'm not understanding what that means at all. Partly that's presentation; is this intended to be how the library would say something, or how the caller would invoke the function? >>>>>>> If the former, I don't understand what it means. If the latter, are you seriously suggesting this as a replacement for >>>>>>> threaded_nut(required, args, here, optional_generic_arc=its_value); >>>>>> I am suggesting it as a replacement for the latter; not because it's better for the user, but because it's better for the maintainers and not worse for the users. (I would assume we'd add `using bosl2::threading` to shorten names, at some point). >>>>>> >>>>>> As a practical example, here is a invocation of a threaded module in my code: >>>>>> >>>>>> buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK); >>>>>> >>>>>> here's how I would do it with the builder pattern and the suggested OO approach: >>>>>> >>>>>> buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify; >>>>>> >>>>>> You don't have to use the builder pattern. You could choose to use objects as a replacement for Python's **kwargs: >>>>>> >>>>>> buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK)); >>>>>> >>>>>> In this case, buttress_threaded_nut's implementation would change from 50 lines to 11: >>>>>> >>>>>> module buttress_threaded_nut(kwargs) { >>>>>> profile = [ >>>>>> [ -1/2, -0.77], >>>>>> [ -7/16, -0.75], >>>>>> [ 5/16, 0], >>>>>> [ 7/16, 0], >>>>>> [ 7/16, -0.75], >>>>>> [ 1/ 2, -0.77], >>>>>> ]; >>>>>> generic_threaded_nut(struct(kwargs, profile=profile)); >>>>>> } >>>>>> >>>>>> Of course, this isn't OO and makes it harder to detect argument name typos and such. >>>>>> >>>>>> The builder pattern could be implemented as so: >>>>>> >>>>>> // namespace for buttress_threaded_nut_builder >>>>>> obj = struct(generic_threaded_nut_builder::new()); >>>>>> function new() = >>>>>> let ( profile = [ >>>>>> [ -1/2, -0.77], >>>>>> [ -7/16, -0.75], >>>>>> [ 5/16, 0], >>>>>> [ 7/16, 0], >>>>>> [ 7/16, -0.75], >>>>>> [ 1/ 2, -0.77], >>>>>> ]) >>>>>> struct(obj)->profile(profile); >>>>>> >>>>>> so not any more or less difficult to write. What do profile and positioning look like? >>>>>> >>>>>> // namespace of generic_threaded_rod_builder >>>>>> function profile(o is builder_obj, profile) = >>>>>> assert(is_list(profile)) // And other tests independent of other values >>>>>> struct(o,profile=profile); >>>>>> >>>>>> // namespace of attachable_builder >>>>>> function positioning(o is attachable_builder_obj, anchor, spin, orient) = >>>>>> assert(/* tests related to the parameters*/) >>>>>> let( >>>>>> l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>>> is_undef(spin) ? [] : [["spin", spin]], >>>>>> is_undef(orient) ? [] : [["orient", orient]]) >>>>>> ) >>>>>> struct(o,l); >>>>>> >>>>>> Okay, not in love with the repetition in there. But there are some improvements here: >>>>>> >>>>>> 1. Some validation can now stop cluttering the top of so many functions/modules. >>>>>> 2. The `get_radius` function doesn't need its args filled out every time >>>>>> 3. We're reusing attachable instead of needing to redundantly pass it so many args every single time and in every function and module signature. >>>>>> 4. We can match on the old types and convert to objects as needed >>>>>> >>>>>> Unsolved issue: why would -> method invocation not look at the namespace of positioning? I didn't intend it to, but it would do the wrong thing as written; only the calls in the new() methods should add the namespace to the method lookup. This might be best as `object` vs `struct` keywords. >>>>>> Maybe attachable should be a mixin instead of in the class hierarchy. >>>>>> >>>>>> So how would I write this with `this` as currently proposed? >>>>>> >>>>>> function buttress_threaded_nut_builder = >>>>>> let ( profile = [ >>>>>> [ -1/2, -0.77], >>>>>> [ -7/16, -0.75], >>>>>> [ 5/16, 0], >>>>>> [ 7/16, 0], >>>>>> [ 7/16, -0.75], >>>>>> [ 1/ 2, -0.77], >>>>>> ]) >>>>>> object(new_generic_threaded_rod_builder().set_profile(profile), /* all methods on buttress_threaded_nut_builder must be defined here */); >>>>>> >>>>>> // in method list of generic_threaded_rod_builder >>>>>> function set_profile(profile) = >>>>>> assert(is_list(profile)) // And other tests independent of other values >>>>>> object(this,profile=profile); >>>>>> >>>>>> // in method list of attachable_builder >>>>>> function set_positioning(anchor, spin, orient) = >>>>>> assert(/* tests related to the parameters*/) >>>>>> let( >>>>>> l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>>> is_undef(spin) ? [] : [["spin", spin]], >>>>>> is_undef(orient) ? [] : [["orient", orient]]) >>>>>> ) >>>>>> struct(this,l); >>>>>> >>>>>> module reify_buttress_threaded_nut(obj) { >>>>>> reify_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> >>>>>> module reify_threaded_nut(obj) { >>>>>> reify_generic_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK)); >>>>>> >>>>>> >>>>>> ... >>>>>> >>>>>> Less different than I thought. Cascading explicit reify modules are annoying. For this usage the inability to write your own generic methods dispatching on other object types does not hinder anything. The shared namespace means methods and values must have unique names. I think this is supposed to solve name conflicts by having you only need one unique name per file and you put all your constants in there? And methods, I guess, so at the top of f.ex. bosl2/threading.scad there would be: >>>>>> >>>>>> bosl2_threading = object( >>>>>> top_level_constant = 27, >>>>>> function buttress_threaded_nut_builder() = >>>>>> ... >>>>>> ); >>>>>> >>>>>> module reify_buttress_threaded_nut(obj) { >>>>>> bosl2_threading.top_level_constant; // for whatever reason >>>>>> reify_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> I've seen worse. I certainly can't say this rules out `this`. >>>>>> _______________________________________________ >>>>>> 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 >>> _______________________________________________ >>> OpenSCAD mailing list >>> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org> >> _______________________________________________ >> OpenSCAD mailing list >> To unsubscribe send an email to discuss-leave@lists.openscad.org <mailto:discuss-leave@lists.openscad.org>
GB
Glenn Butcher
Fri, Aug 22, 2025 4:09 PM

After learning and using three different object-oriented languages, I
found they all behave a little differently with respect to "OO
principles". If OpenSCAD's objects are yet again different, no problem,
I just go with the flow.

The key thing here for me is, "do OpenSCAD objects let me do something
that facilitates my modeling?"  If 'yes', then I'll figure out how it
works, however it works.  Right now, I'm not seeing such, but that's
okay, I'm just one use-case.

Glenn

On 8/22/2025 8:14 AM, Peter Kriens via Discuss wrote:

This discussion is imho a perfect example of bikeshedding
https://en.wiktionary.org/wiki/bikeshedding. We can discuss this
forever on a forum like this because we're all highly experienced &
opinionated but in the mean time OpenSCAD has no KV pairs ... The
enemy of good is 'better' ... This is exactly how the OEP8 effort got
derailed more than 2 years ago. At a certain moment everybody gets
confused and it dies.

I suggest you make a working PR so we can play with concrete proposals
instead of trying to infer what your sketches mean. If I can use KV
pairs and get some concise way to make methods I happily close my PR
and support yours.

I personally would appreciate a time box so we can make sure this does
not get delayed another two years again.

Peter

On 21 Aug 2025, at 23:18, Cory Cross via Discuss
discuss@lists.openscad.org wrote:

On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss
discuss@lists.openscad.org wrote:

On 21 Aug 2025, at 01:55, Cory Cross via Discuss
discuss@lists.openscad.org wrote:

Objects do NOT have parents so I am not sure what you're talking
about? An object is a flat set of key-value pairs. There is no
hierarchy.

Then they shouldn't be called objects. At least 99% of people who
have or will use OpenSCAD will associate objects with the mainstream
object-oriented languages which all put inheritance front-and-center.
It's day-one "learning Python" material. I don't think there's a
single language with a "this" keyword that doesn't have inheritance.
You're setting up people for confusion.

We are very intentionally not implementing a full blow OO system to
keep OpenSCAD as simple as possible, but not simpler.

Following this logic, not adding it is simpler.

What do you want to be simple: writing SCAD or the implementation of
OpenSCAD? There's often (but not always) a trade-off. Brainfuck is
very simple to implement. You can solve some very complicated
analyses in a single line of Mathematica.

So we already have the power to do builders, it's just slightly
uglier and slower. My question is while settle for "this" when
generic functions are even nicer?

Slightly??? We must live in another universe. There are few types of
code I'd like to write less than this kind of boiler plate code. I
wrote several of these 'OO' systems but they were quite ugly.

"this" refers to the proposal to add a "this" keyword. But what I
wrote shows that, with a couple helper functions, the proposed
object() does not result in substantially simpler code and by the
maxim "keep OpenSCAD as simple as possible, but not simpler",
shouldn't be added.

Then you threw in an a-bom ... and another one. I am getting a bit
desperate and feel this is going way off the track and taking way
too much of my time ...

I am new here so I might not understand the mores in this project.

I am new as well (though a user for many years).

However, in other projects I am used that if you want to derail a PR
you make a fully working counter PR so people can play with the
proposals and compare. I find that you're now just dropping
disruptive ideas ...

I've not found any other discussion of OEP8 and wasn't active at the
time anyway. I am discussing now because now is when I'm here.

It's my impression the "this" keyword is just being added because
people are unfamiliar with other systems. If SCAD was a hybrid
procedural/OO lisp with mutable values like JavaScript, then it'd be
fine to copy their semantics. But it's not and I think you're going
down the wrong road.

I'm trying to prove it by picking bosl2 and showing how I'd refactor
it using the proposed "this" approach or the one I'm proposing,
because ultimately what we want is what makes it easier and faster to
write correct code, right?

Everything I've proposed is quite easy to implement and I'll be happy
to do it and/or collaborate on it.

The danger here is that we spend a lot of time talking back and
forth and then nothing happens again because everything got so
complicated. I think this partly happened with OEP8 and that spent a
lot of time in discussion. There are very good, some crucial, ideas
in that PR that has been idling since 2023.

I also think it's important to keep momentum up.

I know I can be a bit blunt but you can blame it on my Dutch
citizenship ;-)

I can be a bit blunt but you can blame it on my Dutch ancestry :-).

  • Cory Cross

Peter

Actually, plists are better because you can get super methods :-)

I'm on my phone composing this without Internet access, so please
forgive the formatting and mild syntax errors.

On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss
discuss@lists.openscad.org wrote:

You flabbergasted me with the completely different
direction/syntax you took but then at the end I saw that you came
to the conclusion you could do all this also with 'this' and
object? Not good for my blood pressure! :-)

I like the builder approach and it is one of my drivers for the
object work and $this.

BTW, notice that OEP8 also proposed to have modules as expression.
I am currently working on a PR for this. This will allow builders
to also call modules, have modules as variables, and hopefully
modules as methods when we can finally close [the $]this
discussion ...

Peter Kriens

On 19 Aug 2025, at 07:47, Cory Cross via Discuss
discuss@lists.openscad.org wrote:
On 8/16/25 8:49 AM, Jordan Brown wrote:

bosl2::threading::nut_builder::new(required, args,
here)->optional_generic_arg(its_value)->reify();

I'm very sympathetic to the desire to reduce repetition in
argument handling, but I'm not understanding what that means at
all.  Partly that's presentation; is this intended to be how the
library would say something, or how the caller would invoke the
function?
If the former, I don't understand what it means.  If the latter,
are you seriously suggesting this as a replacement for
threaded_nut(required, args, here, optional_generic_arc=its_value);

I am suggesting it as a replacement for the latter; not because
it's better for the user, but because it's better for the
maintainers and not worse for the users. (I would assume we'd add
using bosl2::threading to shorten names, at some point).

As a practical example, here is a invocation of a threaded module
in my code:

buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK);

here's how I would do it with the builder pattern and the
suggested OO approach:

buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify;

You don't have to use the builder pattern. You could choose to
use objects as a replacement for Python's **kwargs:

buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK));

In this case, buttress_threaded_nut's implementation would change
from 50 lines to 11:

module buttress_threaded_nut(kwargs) {
  profile = [
      [  -1/2, -0.77],
      [ -7/16, -0.75],
      [  5/16,  0],
      [  7/16,  0],
      [  7/16, -0.75],
      [  1/ 2, -0.77],
  ];
  generic_threaded_nut(struct(kwargs, profile=profile));
}

Of course, this isn't OO and makes it harder to detect argument
name typos and such.

The builder pattern could be implemented as so:

// namespace for buttress_threaded_nut_builder
obj = struct(generic_threaded_nut_builder::new());
function new() =
  let ( profile = [
      [  -1/2, -0.77],
      [ -7/16, -0.75],
      [  5/16,  0],
      [  7/16,  0],
      [  7/16, -0.75],
      [  1/ 2, -0.77],
  ])
  struct(obj)->profile(profile);

so not any more or less difficult to write. What do profile and
positioning look like?

// namespace of generic_threaded_rod_builder
function profile(o is builder_obj, profile) =
  assert(is_list(profile)) // And other tests independent of
other values
  struct(o,profile=profile);

// namespace of attachable_builder
function positioning(o is attachable_builder_obj, anchor, spin,
orient) =
  assert(/* tests related to the parameters*/)
  let(
      l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
         is_undef(spin) ? [] : [["spin", spin]],
         is_undef(orient) ? [] : [["orient", orient]])
      )
  struct(o,l);

Okay, not in love with the repetition in there. But there are
some improvements here:

  1. Some validation can now stop cluttering the top of so many
    functions/modules.
  2. The get_radius function doesn't need its args filled out
    every time
  3. We're reusing attachable instead of needing to redundantly
    pass it so many args every single time and in every function and
    module signature.
  4. We can match on the old types and convert to objects as needed

Unsolved issue: why would -> method invocation not look at the
namespace of positioning? I didn't intend it to, but it would do
the wrong thing as written; only the calls in the new() methods
should add the namespace to the method lookup. This might be best
as object vs struct keywords.
Maybe attachable should be a mixin instead of in the class hierarchy.

So how would I write this with this as currently proposed?

function buttress_threaded_nut_builder =
  let ( profile = [
      [  -1/2, -0.77],
      [ -7/16, -0.75],
      [  5/16,  0],
      [  7/16,  0],
      [  7/16, -0.75],
      [  1/ 2, -0.77],
  ])
  object(new_generic_threaded_rod_builder().set_profile(profile),
/* all methods on buttress_threaded_nut_builder must be defined
here */);

// in method list of generic_threaded_rod_builder
function set_profile(profile) =
  assert(is_list(profile)) // And other tests independent of
other values
  object(this,profile=profile);

// in method list of attachable_builder
function set_positioning(anchor, spin, orient) =
  assert(/* tests related to the parameters*/)
  let(
      l = concat(is_undef(anchor) ? [] : [["anchor", anchor]],
         is_undef(spin) ? [] : [["spin", spin]],
         is_undef(orient) ? [] : [["orient", orient]])
      )
  struct(this,l);

module reify_buttress_threaded_nut(obj) {
  reify_threaded_nut(obj);
}

module reify_threaded_nut(obj) {
  reify_generic_threaded_nut(obj);
}

reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK));

...

Less different than I thought. Cascading explicit reify modules
are annoying. For this usage the inability to write your own
generic methods dispatching on other object types does not hinder
anything. The shared namespace means methods and values must have
unique names. I think this is supposed to solve name conflicts by
having you only need one unique name per file and you put all
your constants in there? And methods, I guess, so at the top of
f.ex. bosl2/threading.scad there would be:

bosl2_threading = object(
  top_level_constant = 27,
  function buttress_threaded_nut_builder() =
...
);

module reify_buttress_threaded_nut(obj) {
  bosl2_threading.top_level_constant; // for whatever reason
  reify_threaded_nut(obj);
}

I've seen worse. I certainly can't say this rules out this.


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


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


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

After learning and using three different object-oriented languages, I found they all behave a little differently with respect to "OO principles". If OpenSCAD's objects are yet again different, no problem, I just go with the flow. The key thing here for me is, "do OpenSCAD objects let me do something that facilitates my modeling?"  If 'yes', then I'll figure out how it works, however it works.  Right now, I'm not seeing such, but that's okay, I'm just one use-case. Glenn On 8/22/2025 8:14 AM, Peter Kriens via Discuss wrote: > This discussion is imho a perfect example of bikeshedding > <https://en.wiktionary.org/wiki/bikeshedding>. We can discuss this > forever on a forum like this because we're all highly experienced & > opinionated but in the mean time OpenSCAD has no KV pairs ... The > enemy of good is 'better' ... This is exactly how the OEP8 effort got > derailed more than 2 years ago. At a certain moment everybody gets > confused and it dies. > > I suggest you make a working PR so we can play with concrete proposals > instead of trying to infer what your sketches mean. If I can use KV > pairs and get some concise way to make methods I happily close my PR > and support yours. > > I personally would appreciate a time box so we can make sure this does > not get delayed another two years again. > > Peter > > >> On 21 Aug 2025, at 23:18, Cory Cross via Discuss >> <discuss@lists.openscad.org> wrote: >> >> >> >> On August 21, 2025 9:57:30 AM EDT, Peter Kriens via Discuss >> <discuss@lists.openscad.org> wrote: >>>> On 21 Aug 2025, at 01:55, Cory Cross via Discuss >>>> <discuss@lists.openscad.org> wrote: >>> Objects do NOT have parents so I am not sure what you're talking >>> about? An object is a flat set of key-value pairs. There is no >>> hierarchy. >> >> Then they shouldn't be called objects. At least 99% of people who >> have or will use OpenSCAD will associate objects with the mainstream >> object-oriented languages which all put inheritance front-and-center. >> It's day-one "learning Python" material. I don't think there's a >> single language with a "this" keyword that doesn't have inheritance. >> You're setting up people for confusion. >> >>> We are very intentionally not implementing a full blow OO system to >>> keep OpenSCAD as simple as possible, but not simpler. >> >> Following this logic, not adding it is simpler. >> >> What do you want to be simple: writing SCAD or the implementation of >> OpenSCAD? There's often (but not always) a trade-off. Brainfuck is >> very simple to implement. You can solve some very complicated >> analyses in a single line of Mathematica. >> >>>> So we already have the power to do builders, it's just slightly >>>> uglier and slower. My question is while settle for "this" when >>>> generic functions are even nicer? >>> >>> Slightly??? We must live in another universe. There are few types of >>> code I'd like to write less than this kind of boiler plate code. I >>> wrote several of these 'OO' systems but they were quite ugly. >> >> "this" refers to the proposal to add a "this" keyword. But what I >> wrote shows that, with a couple helper functions, the proposed >> object() does not result in substantially simpler code and by the >> maxim "keep OpenSCAD as simple as possible, but not simpler", >> shouldn't be added. >> >>> Then you threw in an a-bom ... and another one. I am getting a bit >>> desperate and feel this is going way off the track and taking way >>> too much of my time ... >>> >>> I am new here so I might not understand the mores in this project. >> >> I am new as well (though a user for many years). >> >>> However, in other projects I am used that if you want to derail a PR >>> you make a fully working counter PR so people can play with the >>> proposals and compare. I find that you're now just dropping >>> disruptive ideas ... >> >> I've not found any other discussion of OEP8 and wasn't active at the >> time anyway. I am discussing now because now is when I'm here. >> >> It's my impression the "this" keyword is just being added because >> people are unfamiliar with other systems. If SCAD was a hybrid >> procedural/OO lisp with mutable values like JavaScript, then it'd be >> fine to copy their semantics. But it's not and I think you're going >> down the wrong road. >> >> I'm trying to prove it by picking bosl2 and showing how I'd refactor >> it using the proposed "this" approach or the one I'm proposing, >> because ultimately what we want is what makes it easier and faster to >> write correct code, right? >> >> Everything I've proposed is quite easy to implement and I'll be happy >> to do it and/or collaborate on it. >> >>> The danger here is that we spend a lot of time talking back and >>> forth and then nothing happens again because everything got so >>> complicated. I think this partly happened with OEP8 and that spent a >>> lot of time in discussion. There are very good, some crucial, ideas >>> in that PR that has been idling since 2023. >> >> I also think it's important to keep momentum up. >> >>> I know I can be a bit blunt but you can blame it on my Dutch >>> citizenship ;-) >> >> I can be a bit blunt but you can blame it on my Dutch ancestry :-). >> >> - Cory Cross >> >>> >>> Peter >>> >>> >>> >>>> >>>> Actually, plists are better because you can get super methods :-) >>>> >>>> >>>> I'm on my phone composing this without Internet access, so please >>>> forgive the formatting and mild syntax errors. >>>> >>>> >>>> >>>> On August 19, 2025 4:40:20 AM EDT, Peter Kriens via Discuss >>>> <discuss@lists.openscad.org> wrote: >>>>> You flabbergasted me with the completely different >>>>> direction/syntax you took but then at the end I saw that you came >>>>> to the conclusion you could do all this also with 'this' and >>>>> `object`? Not good for my blood pressure! :-) >>>>> >>>>> I like the builder approach and it is one of my drivers for the >>>>> object work and $this. >>>>> >>>>> BTW, notice that OEP8 also proposed to have modules as expression. >>>>> I am currently working on a PR for this. This will allow builders >>>>> to also call modules, have modules as variables, and hopefully >>>>> modules as methods when we can finally close [the $]this >>>>> discussion ... >>>>> >>>>> Peter Kriens >>>>> >>>>>> On 19 Aug 2025, at 07:47, Cory Cross via Discuss >>>>>> <discuss@lists.openscad.org> wrote: >>>>>> On 8/16/25 8:49 AM, Jordan Brown wrote: >>>>>>>> bosl2::threading::nut_builder::new(required, args, >>>>>>>> here)->optional_generic_arg(its_value)->reify(); >>>>>>> I'm very sympathetic to the desire to reduce repetition in >>>>>>> argument handling, but I'm not understanding what that means at >>>>>>> all.  Partly that's presentation; is this intended to be how the >>>>>>> library would say something, or how the caller would invoke the >>>>>>> function? >>>>>>> If the former, I don't understand what it means.  If the latter, >>>>>>> are you seriously suggesting this as a replacement for >>>>>>> threaded_nut(required, args, here, optional_generic_arc=its_value); >>>>>> I am suggesting it as a replacement for the latter; not because >>>>>> it's better for the user, but because it's better for the >>>>>> maintainers and not worse for the users. (I would assume we'd add >>>>>> `using bosl2::threading` to shorten names, at some point). >>>>>> >>>>>> As a practical example, here is a invocation of a threaded module >>>>>> in my code: >>>>>> >>>>>> buttress_threaded_nut(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK); >>>>>> >>>>>> here's how I would do it with the builder pattern and the >>>>>> suggested OO approach: >>>>>> >>>>>> buttress_threaded_nut_builder::new()->nutwidth(10)->id(7+.17*4)->h(6)->shape("square")->positioning(orient=DOWN,anchor=TOP+BACK)->reify; >>>>>> >>>>>> You don't have to use the builder pattern. You could choose to >>>>>> use objects as a replacement for Python's **kwargs: >>>>>> >>>>>> buttress_threaded_nut(struct(nutwidth=10,id=7+.17*4,h=6,pitch=1,shape="square",orient=DOWN,anchor=TOP+BACK)); >>>>>> >>>>>> In this case, buttress_threaded_nut's implementation would change >>>>>> from 50 lines to 11: >>>>>> >>>>>> module buttress_threaded_nut(kwargs) { >>>>>>   profile = [ >>>>>>       [  -1/2, -0.77], >>>>>>       [ -7/16, -0.75], >>>>>>       [  5/16,  0], >>>>>>       [  7/16,  0], >>>>>>       [  7/16, -0.75], >>>>>>       [  1/ 2, -0.77], >>>>>>   ]; >>>>>>   generic_threaded_nut(struct(kwargs, profile=profile)); >>>>>> } >>>>>> >>>>>> Of course, this isn't OO and makes it harder to detect argument >>>>>> name typos and such. >>>>>> >>>>>> The builder pattern could be implemented as so: >>>>>> >>>>>> // namespace for buttress_threaded_nut_builder >>>>>> obj = struct(generic_threaded_nut_builder::new()); >>>>>> function new() = >>>>>>   let ( profile = [ >>>>>>       [  -1/2, -0.77], >>>>>>       [ -7/16, -0.75], >>>>>>       [  5/16,  0], >>>>>>       [  7/16,  0], >>>>>>       [  7/16, -0.75], >>>>>>       [  1/ 2, -0.77], >>>>>>   ]) >>>>>>   struct(obj)->profile(profile); >>>>>> >>>>>> so not any more or less difficult to write. What do profile and >>>>>> positioning look like? >>>>>> >>>>>> // namespace of generic_threaded_rod_builder >>>>>> function profile(o is builder_obj, profile) = >>>>>>   assert(is_list(profile)) // And other tests independent of >>>>>> other values >>>>>>   struct(o,profile=profile); >>>>>> >>>>>> // namespace of attachable_builder >>>>>> function positioning(o is attachable_builder_obj, anchor, spin, >>>>>> orient) = >>>>>>   assert(/* tests related to the parameters*/) >>>>>>   let( >>>>>>       l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>>>          is_undef(spin) ? [] : [["spin", spin]], >>>>>>          is_undef(orient) ? [] : [["orient", orient]]) >>>>>>       ) >>>>>>   struct(o,l); >>>>>> >>>>>> Okay, not in love with the repetition in there. But there are >>>>>> some improvements here: >>>>>> >>>>>> 1. Some validation can now stop cluttering the top of so many >>>>>> functions/modules. >>>>>> 2. The `get_radius` function doesn't need its args filled out >>>>>> every time >>>>>> 3. We're reusing attachable instead of needing to redundantly >>>>>> pass it so many args every single time and in every function and >>>>>> module signature. >>>>>> 4. We can match on the old types and convert to objects as needed >>>>>> >>>>>> Unsolved issue: why would -> method invocation not look at the >>>>>> namespace of positioning? I didn't intend it to, but it would do >>>>>> the wrong thing as written; only the calls in the new() methods >>>>>> should add the namespace to the method lookup. This might be best >>>>>> as `object` vs `struct` keywords. >>>>>> Maybe attachable should be a mixin instead of in the class hierarchy. >>>>>> >>>>>> So how would I write this with `this` as currently proposed? >>>>>> >>>>>> function buttress_threaded_nut_builder = >>>>>>   let ( profile = [ >>>>>>       [  -1/2, -0.77], >>>>>>       [ -7/16, -0.75], >>>>>>       [  5/16,  0], >>>>>>       [  7/16,  0], >>>>>>       [  7/16, -0.75], >>>>>>       [  1/ 2, -0.77], >>>>>>   ]) >>>>>>   object(new_generic_threaded_rod_builder().set_profile(profile), >>>>>> /* all methods on buttress_threaded_nut_builder must be defined >>>>>> here */); >>>>>> >>>>>> // in method list of generic_threaded_rod_builder >>>>>> function set_profile(profile) = >>>>>>   assert(is_list(profile)) // And other tests independent of >>>>>> other values >>>>>>   object(this,profile=profile); >>>>>> >>>>>> // in method list of attachable_builder >>>>>> function set_positioning(anchor, spin, orient) = >>>>>>   assert(/* tests related to the parameters*/) >>>>>>   let( >>>>>>       l = concat(is_undef(anchor) ? [] : [["anchor", anchor]], >>>>>>          is_undef(spin) ? [] : [["spin", spin]], >>>>>>          is_undef(orient) ? [] : [["orient", orient]]) >>>>>>       ) >>>>>>   struct(this,l); >>>>>> >>>>>> module reify_buttress_threaded_nut(obj) { >>>>>>   reify_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> >>>>>> module reify_threaded_nut(obj) { >>>>>>   reify_generic_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> reify_buttress_threaded_nut(buttress_threaded_nut_builder().set_nutwidth(10)->set_id(7+.17*4)->set_h(6)->set_shape("square")->set_positioning(orient=DOWN,anchor=TOP+BACK)); >>>>>> >>>>>> >>>>>> ... >>>>>> >>>>>> Less different than I thought. Cascading explicit reify modules >>>>>> are annoying. For this usage the inability to write your own >>>>>> generic methods dispatching on other object types does not hinder >>>>>> anything. The shared namespace means methods and values must have >>>>>> unique names. I think this is supposed to solve name conflicts by >>>>>> having you only need one unique name per file and you put all >>>>>> your constants in there? And methods, I guess, so at the top of >>>>>> f.ex. bosl2/threading.scad there would be: >>>>>> >>>>>> bosl2_threading = object( >>>>>>   top_level_constant = 27, >>>>>>   function buttress_threaded_nut_builder() = >>>>>> ... >>>>>> ); >>>>>> >>>>>> module reify_buttress_threaded_nut(obj) { >>>>>>   bosl2_threading.top_level_constant; // for whatever reason >>>>>>   reify_threaded_nut(obj); >>>>>> } >>>>>> >>>>>> I've seen worse. I certainly can't say this rules out `this`. >>>>>> _______________________________________________ >>>>>> 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 >>> _______________________________________________ >>> 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 > > > _______________________________________________ > OpenSCAD mailing list > To unsubscribe send an email todiscuss-leave@lists.openscad.org
LM
Leonard Martin Struttmann
Fri, Aug 22, 2025 6:05 PM

Let's stop trying to make them objects and just call them dictionary, map,
associative array, or any of the many other names for
this: https://en.m.wikipedia.org/wiki/Associative_array
https://en.m.wikipedia.org/wiki/Associative_array

I very much agree with this proposal! This will avoid confusion.

*Let's stop trying to make them objects and just call them dictionary, map, associative array, or any of the many other names for this: https://en.m.wikipedia.org/wiki/Associative_array <https://en.m.wikipedia.org/wiki/Associative_array>* I very much agree with this proposal! This will avoid confusion.