[OpenSCAD] Proposal for extensions to the OpenSCAD syntax

A. Craig West acraigwest at gmail.com
Mon Oct 28 07:56:58 EDT 2019


I know that in my library, I created a draw module, with a large number of
arguments to control how it rendered the children. It was a wrapper around
what was essentially a large switch case, so you could control things like
the % operator with boolean flags,as well as things like colour and alpha.
The code is terrible from a programmers point of view, but it makes it much
easier to turn on and off multiple sections of the display by only editing
a few variables. Most of my designs were intended for the thingiverse
customiser, so this method of working makes a lot of sense

On Mon, 28 Oct 2019, 07:09 nop head, <nop.head at gmail.com> wrote:

> Well I consider my way of working more object oriented. A class normally
> has lots of different methods named Class::method and with an implicit
> *this* pointer or *self* reference. I just do this explicitly with
> class_method(type).
>
> I don't see any connection between adding and subtracting objects with
> constructors and destructors. The latter are about object lifetime and
> there is no such concept in OpenSCAD because it is a static description.
>
> I also don't see your point about a proliferation of modules. I think of a
> used OpenSCAD file as a class and the modules and functions as methods. You
> seem to be treating a module as a class and trying to access things inside
> of it. I consider the internals of my modules private and expose and
> interface to my objects with functions.
>
> On Mon, 28 Oct 2019 at 09:43, Hugo Jackson <hugo at apres.net> wrote:
>
>>
>>
>> On Oct 28, 2019, at 1:51 AM, nop head <nop.head at gmail.com> wrote:
>>
>> Instead of
>>
>> module bar() {
>>         union : {
>>                 foo.union();
>>                 _cylinder(d = 5, h = 10);
>>         }
>>         diff : {
>>                 foo.diff();
>>         }
>> }
>>
>> Why don't you simply define two modules foo_union() and foo_diff()?
>>
>> In conventional programming it is bonkers to have combine two
>> completely different bits of code in one function and pass a global
>> variable to decide which one is executed.
>>
>> In my case I would have foo(type), foo_holes(type) where type is a list
>> with all the parameters and I have accessor functions such as
>> foo_width(type).
>>
>> If there is common positioning between foo() and foo_holes() then I would
>> have foo_hole_positions(type) that positions children().
>>
>>
>> I take your point, and the distributed functionality of the modules you
>> recommend is something I have tried and eventually abandoned… I think I
>> just found the proliferation of modules a little unsatisfying.
>>
>> I think my current direction is shaped by my experience with object
>> oriented programming… indeed, in OpenSCAD I’m primarily creating actual
>> objects :)
>>
>> So to my way of thinking, and I’d be the first to concede that I may not
>> have the experience to really warrant an opinion, some adoption of object
>> oriented philosophy would improve the OpenSCAD programming experience even
>> if its not an object oriented language.
>>
>> So while in a conventional imperative language it may be insane to
>> combine two bits of code whose execution is selected by a passed parameter,
>> what I’m trying to do is get at least some feel for a more oo like
>> environment even though the language doesn’t support it, and my proposal to
>> do that is part of that goal, and that’s the reason for my proposal of
>> extended dot notation… the ability to call the ‘methods’ of OpenSCAD
>> objects seems natural to me.
>>
>> The second part of the proposal whether it’s accomplished with labels or
>> ‘reserved’ methods is just my attempt to suggest something that might feel
>> something like the constructor/destructor functions of an oo object. With
>> ‘real’ objects like in OpenSCAD I liken the union method to a constructor
>> and the difference/intersection functionality to a destructor and my
>> proposal was aimed at incorporating the benefits of that kind of structure
>> to an OpenSCAD program.
>>
>> Anyway, thanks for you feedback, it's helping me to develop a better
>> understanding of what I’m wishing for, even if that desire is unrealistic,
>> impractical or unachievable.
>>
>>
>>
>> On Mon, 28 Oct 2019 at 04:25, Hugo Jackson <hugo at apres.net> wrote:
>>
>>>
>>>
>>> > On Oct 27, 2019, at 5:13 PM, Torsten Paul <Torsten.Paul at gmx.de> wrote:
>>> >
>>> > First note that the function literals are now
>>> > implemented, so the snapshot version of OpenSCAD
>>> > has functions as first class values which means
>>> > support for higher order functions.
>>> > (https://github.com/openscad/openscad/pull/3077)
>>> >
>>> > I hope to find some time to collect notes and post
>>> > an article about it. Meanwhile the minimalist docu
>>> > can be found at
>>> >
>>> https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/User-Defined_Functions_and_Modules#Function_Literals
>>> >
>>> > On 28.10.19 00:09, Hugo Jackson wrote:
>>> >> To start, I would propose an extension of the "dot"
>>> >> notation, that would allow one to refer to a value
>>> >> declaration and/or function or module component of
>>> >> another module with a dot.
>>> >
>>> > Yes, having access to a nested data structure is
>>> > definitely something that would help a lot. The
>>> > core changes to the parser implementation that are
>>> > required for this are now done and merged to the
>>> > development snapshot.
>>> >
>>> > But I don't think it will be possible to link to
>>> > the existing function and/or module definitions.
>>> >
>>> > Slightly modified example, just adding a parameter
>>> > to module foo():
>>> >
>>> > module foo(offset) {
>>> >       valueA = 7 + offset;
>>> >
>>> >       function myFunc(num) = valueA + num;
>>> > }
>>> >
>>> > module bar() {
>>> >       valueB = 8;
>>> >
>>> >       valueC = foo.valueA + foo.myFunc(valueB);
>>> > }
>>> >
>>> > foo(10);
>>> > translate([10, 10, 0]) foo(20);
>>> >
>>> > bar(); // <- now what is valueC ?
>>> >
>>>
>>> Good point… for my part I don’t usually code modules with parameters,
>>> but I appreciate that isn’t how the real world works. :)
>>> But I would think that calling any module part or function would require
>>> an enumeration of all needed values in the parameter arguments, e.g. for
>>> the example you
>>> provide the call for valueC in bar would need to be:
>>>
>>> valueC = foo(offset = 7).valueA + foo(offset = 7).myFunc(valueB) … or
>>> literally valueC = foo(7).valueA + foot(7).myFunc(valueB)
>>>
>>> Perhaps that would lead to a preponderance of code that would only serve
>>> to make code look more tortuous than it already does. Yet I think the
>>> proposed ‘dot’ syntax would lead to more insightful coding that would
>>> tend to mitigate the damage that might occur.
>>>
>>> >
>>> >> The second extension would be the election of three
>>> >> operations as 'reserved' functions, union, difference
>>> >> and intersection such that one could explicitly call
>>> >> that part of a module without calling the others:
>>> >
>>> > I'm not sure I understand how this will work. Why
>>> > select specifically those 3 special cases?
>>> >
>>> > Is that meant just as names or would that also mean
>>> > intersection() { bar(); foo(); } a bit like operator
>>> > overloading?
>>> >
>>> >> foo(); // would execute intersection(){difference(){union(){<union
>>> code>}<difference code>}<intersection code>}
>>> >
>>> > Where's the nesting coming from? From the order of
>>> > the definitions?
>>> >
>>> >> Please let me know… I didn’t want to bog this
>>> >> proposal down with details if it’s obvious, but in
>>> >> doing that I have taken the risk that the improvement
>>> >> And benefits of such extensions may not be evident.
>>>
>>>
>>>
>>> I often code modules using a special varialble I name $e and a skeleton
>>> module that looks like this:
>>>
>>> module foo($e = -1) {
>>>         module _union() {
>>>                 // code that primarily builds the object
>>>         }
>>>
>>>         module _diff() {
>>>                 // code that primarily subtracts geometry from _union()
>>>         }
>>>
>>>         difference() {
>>>                 if($e == -1 || $e == 0)
>>>                         _union();
>>>                 if($e == -1 || $e == 1)
>>>                         _diff();
>>>         }
>>> }
>>>
>>> I then get to call foo and either get just the _union code or just the
>>> _diff code or have the object definition run completely when $e == -1
>>>
>>> With this approach, when I just want the foo object I simply write:
>>>
>>> foo();
>>>
>>> But if I want the foo object to be united with some other objects before
>>> any difference is applied I could do it like this:
>>>
>>> module bar() {
>>>         difference() {
>>>                 union() {
>>>                         foo($e = 0);
>>>                         cylinder(d = 5, h = 10);
>>>                 }
>>>                 foo($e = 1);
>>>         }
>>> }
>>>
>>> I find that this kind of approach helps with the overall flow and data
>>> abstraction, but the addition of a special variable and the requirement for
>>> the difference(){union() {}} code to make it work detracts from what I feel
>>> is overall a more elegant approach, and I find it particularly helpful for
>>> code reuse.
>>> So that’s really what my suggestion for ’reserved’ functions is about..
>>> following the logic that you would execute union functionality before
>>> difference because you need to have first constructed an object before you
>>> remove anything from it. Don’t almost all modules have the…
>>>
>>> difference() {
>>>         union() {
>>>                 // add some stuff
>>>         }
>>>         // take some stuff away
>>> }
>>>
>>> construct in them?
>>>
>>> So that’s why I was thinking that a syntax that supported what I have at
>>> least found to be the most common code construction would make code more
>>> readable, so that I would just write:
>>>
>>> module foo() {
>>>
>>>         union : {
>>>                 // code that primarily builds the object
>>>         }
>>>         diff : {
>>>                 // code that primarily subtracts geometry from union()
>>>         }
>>>
>>>         // code that follows executes only if foo is called
>>> }
>>>
>>> Now when I want the foo object to be combined with other objects, I
>>> would just have to write:
>>>
>>> module bar() {
>>>         union : {
>>>                 foo.union();
>>>                 _cylinder(d = 5, h = 10);
>>>         }
>>>         diff : {
>>>                 foo.diff();
>>>         }
>>> }
>>>
>>> Perhaps there may be a more elegant way of structuring things, but I was
>>> aiming at a syntax that while not backwards compatible, wouldn’t break
>>> anything that was already working.
>>>
>>> Thanks for the heads up on the availability of function literals… that
>>> should make life more fun and exciting. And thanks for the links to the
>>> discussion lists.
>>>
>>>
>>>
>>> _______________________________________________
>>> OpenSCAD mailing list
>>> Discuss at lists.openscad.org
>>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>>
>> _______________________________________________
>> OpenSCAD mailing list
>> Discuss at lists.openscad.org
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
>>
>> _______________________________________________
>> OpenSCAD mailing list
>> Discuss at lists.openscad.org
>> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>>
> _______________________________________________
> OpenSCAD mailing list
> Discuss at lists.openscad.org
> http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.openscad.org/pipermail/discuss_lists.openscad.org/attachments/20191028/d056492d/attachment.html>


More information about the Discuss mailing list