discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Bundling module parameters

T
ThumbOne
Wed, Apr 29, 2020 4:26 AM

This time I have an interesting syntax question. I'm building a small library
of bits I find useful and in the manner of such libraries more complex parts
build on simpler parts.

Even the simple part may have a good few parameters. For example:

module simple_thing(p1, p2, p3, p4, p5, p6) { }

Now I want to build on that, create a richer model of something bigger and
more complicated and I want to bundle these parameters into a vector
something like this:

module bigger_thing(simple_thing_ps, pp11, pp2) { }

where:

simple_thing_ps = [p1, p2, p3, p4, p5, p6]

that is, the simple thing parameters bundled up. In this bigger module now I
can include a simple thing like so quite easily:

module bigger_thing(simple_thing_ps, pp11, pp2) {

    simple_thing(simple_thing_ps[0],

simple_thing_ps[1],simple_thing_ps[2],
simple_thing_ps[3],simple_thing_ps[4], simple_thing_ps[5]);

    // do more stuff

}

But wow that is clumsy. Now I'm familiar with Python and it has a beautiful
syntax for unpacking lists like this, so that I could write something like:

module bigger_thing(simple_thing_ps, pp11, pp2) {

    simple_thing(unpack(simple_thing_ps));

    // do more stuff

}

Not only terser and nicer, the new module no longer needs to know how long
simple_thing_ps is. In Python that unpack operarator is just *, such that
the if the v = [p1, p2, p3], then *v = p1, p2, p3 and I'd call
simple_thing(*v) to have the list unpacked into individual parameters that
simple thing sees.

Of course one solution is to write simple_thing so it takes a single vector
parameter which it unpacks internally into parameters. But that too is
clumsy, as it means anyone using simple_thing has an odd syntax to contend
with.

I've had a look at "each" which tantalisingly close and may even be able to
do this, I just haven't figured outhow yet.

https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#each

All the examples are generating lists, rather than unpacking them. There's a
solid chance that unpack simply isn't possible.

Perhaps one smart flexible way to write it is to have simple_thing check if
it has only one vector as a parameter, and if so unpack it internally else
use the parameters themselves.

module simple_thing(p, p2, p3, p4, p5, p6) {
if (is_list(p) && is_undef(p2)
&& is_undef(p3)
&& is_undef(p4)
&& is_undef(p5)
&& is_undef(p6) ) {
p1 = p[0];
p2 = p[1];
p3 = p[2];
p4 = p[3];
p5 = p[4];
p6 = p[5];
} else {
p1 = p
}
}

While a little wordy it's contain in simple_thing and allows using it
normally and tersely in bigger things. It just gets a little hairier if some
or all of the parameters have default values and if p is expected to be a
list anyhow etc.

Wonder if there's a more elegant solution?

Regards,

Bernd.

--
Sent from: http://forum.openscad.org/

This time I have an interesting syntax question. I'm building a small library of bits I find useful and in the manner of such libraries more complex parts build on simpler parts. Even the simple part may have a good few parameters. For example: module simple_thing(p1, p2, p3, p4, p5, p6) { } Now I want to build on that, create a richer model of something bigger and more complicated and I want to bundle these parameters into a vector something like this: module bigger_thing(simple_thing_ps, pp11, pp2) { } where: simple_thing_ps = [p1, p2, p3, p4, p5, p6] that is, the simple thing parameters bundled up. In this bigger module now I can include a simple thing like so quite easily: module bigger_thing(simple_thing_ps, pp11, pp2) { simple_thing(simple_thing_ps[0], simple_thing_ps[1],simple_thing_ps[2], simple_thing_ps[3],simple_thing_ps[4], simple_thing_ps[5]); // do more stuff } But wow that is clumsy. Now I'm familiar with Python and it has a beautiful syntax for unpacking lists like this, so that I could write something like: module bigger_thing(simple_thing_ps, pp11, pp2) { simple_thing(unpack(simple_thing_ps)); // do more stuff } Not only terser and nicer, the new module no longer needs to know how long simple_thing_ps is. In Python that unpack operarator is just *, such that the if the v = [p1, p2, p3], then *v = p1, p2, p3 and I'd call simple_thing(*v) to have the list unpacked into individual parameters that simple thing sees. Of course one solution is to write simple_thing so it takes a single vector parameter which it unpacks internally into parameters. But that too is clumsy, as it means anyone using simple_thing has an odd syntax to contend with. I've had a look at "each" which tantalisingly close and may even be able to do this, I just haven't figured outhow yet. https://en.wikibooks.org/wiki/OpenSCAD_User_Manual/List_Comprehensions#each All the examples are generating lists, rather than unpacking them. There's a solid chance that unpack simply isn't possible. Perhaps one smart flexible way to write it is to have simple_thing check if it has only one vector as a parameter, and if so unpack it internally else use the parameters themselves. module simple_thing(p, p2, p3, p4, p5, p6) { if (is_list(p) && is_undef(p2) && is_undef(p3) && is_undef(p4) && is_undef(p5) && is_undef(p6) ) { p1 = p[0]; p2 = p[1]; p3 = p[2]; p4 = p[3]; p5 = p[4]; p6 = p[5]; } else { p1 = p } } While a little wordy it's contain in simple_thing and allows using it normally and tersely in bigger things. It just gets a little hairier if some or all of the parameters have default values and if p is expected to be a list anyhow etc. Wonder if there's a more elegant solution? Regards, Bernd. -- Sent from: http://forum.openscad.org/
RW
Rogier Wolff
Wed, Apr 29, 2020 5:56 AM

On Tue, Apr 28, 2020 at 09:26:25PM -0700, ThumbOne via Discuss wrote:

Wonder if there's a more elegant solution?

I'd make a

module simple_thing_v (pv)  // simple thing with a vector for the parameters.
{
simple_thing (pv[1], pv[2], pv[3], pv[4], pv[5]);
}

Roger. 

--
** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 **
**    Delftechpark 11 2628 XJ  Delft, The Netherlands.  KVK: 27239233    **
The plan was simple, like my brother-in-law Phil. But unlike
Phil, this plan just might work.

On Tue, Apr 28, 2020 at 09:26:25PM -0700, ThumbOne via Discuss wrote: > Wonder if there's a more elegant solution? I'd make a module simple_thing_v (pv) // simple thing with a vector for the parameters. { simple_thing (pv[1], pv[2], pv[3], pv[4], pv[5]); } Roger. -- ** R.E.Wolff@BitWizard.nl ** https://www.BitWizard.nl/ ** +31-15-2049110 ** ** Delftechpark 11 2628 XJ Delft, The Netherlands. KVK: 27239233 ** The plan was simple, like my brother-in-law Phil. But unlike Phil, this plan just might work.
RP
Ronaldo Persiano
Wed, Apr 29, 2020 9:56 AM

Functions with alternative parameter sets are harder to write and clumsy to
read. When possible, avoid it. If needed, define clear precedence rules.

What would be the result of your last code for a call like:

simple_thing([1, 2], 3)  ;

Functions with alternative parameter sets are harder to write and clumsy to read. When possible, avoid it. If needed, define clear precedence rules. What would be the result of your last code for a call like: simple_thing([1, 2], 3) ;
A
adrianv
Wed, Apr 29, 2020 10:34 AM

Ronaldo wrote

Functions with alternative parameter sets are harder to write and clumsy
to
read. When possible, avoid it. If needed, define clear precedence rules.

Harder to write, absolutely.  Careful parameter checking is necessary.  In
the posted example I would check that either all five parameters are defined
or only the first one is defined.  Otherwise, issue an error.  And then if
you have one parameter, split it with a recursive call.

But clumsy to read?  I disagree.  What's clumsy to read (and write in my
code) are a bunch of calls where you have to use double delimiters so you
have

foobar([v1,v2,v3]);
baz([v2,v3]);

instead of simply

foobar(v1,v2,v3);
baz(v2,v3);

--
Sent from: http://forum.openscad.org/

Ronaldo wrote > Functions with alternative parameter sets are harder to write and clumsy > to > read. When possible, avoid it. If needed, define clear precedence rules. Harder to write, absolutely. Careful parameter checking is necessary. In the posted example I would check that either all five parameters are defined or only the first one is defined. Otherwise, issue an error. And then if you have one parameter, split it with a recursive call. But clumsy to read? I disagree. What's clumsy to read (and write in my code) are a bunch of calls where you have to use double delimiters so you have foobar([v1,v2,v3]); baz([v2,v3]); instead of simply foobar(v1,v2,v3); baz(v2,v3); -- Sent from: http://forum.openscad.org/
RP
Ronaldo Persiano
Wed, Apr 29, 2020 11:25 AM

But clumsy to read?  I disagree.  What's clumsy to read (and write in my
code) are a bunch of calls where you have to use double delimiters so you
have

I understand your point but I was referring to the function code reading
not its call.

> > But clumsy to read? I disagree. What's clumsy to read (and write in my > code) are a bunch of calls where you have to use double delimiters so you > have > I understand your point but I was referring to the function code reading not its call.
NH
nop head
Wed, Apr 29, 2020 11:42 AM

I prefer to represent objects by named lists of properties and pass that as
the first parameter to all functions and module that operate on them. That
keeps the code clean and backwards compatible. I.e. I can add more
properties to the list and it does not affect clients of the library as
they still pass the same named object, with no care of what it is.

The only advantage of using module parameters is they can be set by name
and have defaults, whereas my lists are all initialised by position. That
could be solved by having a separate constructor function with an argument
per property to make the lists. However since the lists are hidden away in
the library, each in their own file, there would be little benefit.

There are a few objects that are defined in the client code. Mainly
customisable printed objects like cases. This discussion has prompted me to
think they should have constructor functions to better isolate the client
code from changes to the library.

On Wed, 29 Apr 2020 at 12:26, Ronaldo Persiano rcmpersiano@gmail.com
wrote:

But clumsy to read?  I disagree.  What's clumsy to read (and write in my

code) are a bunch of calls where you have to use double delimiters so you
have

I understand your point but I was referring to the function code reading
not its call.


OpenSCAD mailing list
Discuss@lists.openscad.org
http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org

I prefer to represent objects by named lists of properties and pass that as the first parameter to all functions and module that operate on them. That keeps the code clean and backwards compatible. I.e. I can add more properties to the list and it does not affect clients of the library as they still pass the same named object, with no care of what it is. The only advantage of using module parameters is they can be set by name and have defaults, whereas my lists are all initialised by position. That could be solved by having a separate constructor function with an argument per property to make the lists. However since the lists are hidden away in the library, each in their own file, there would be little benefit. There are a few objects that are defined in the client code. Mainly customisable printed objects like cases. This discussion has prompted me to think they should have constructor functions to better isolate the client code from changes to the library. On Wed, 29 Apr 2020 at 12:26, Ronaldo Persiano <rcmpersiano@gmail.com> wrote: > But clumsy to read? I disagree. What's clumsy to read (and write in my >> code) are a bunch of calls where you have to use double delimiters so you >> have >> > > I understand your point but I was referring to the function code reading > not its call. > _______________________________________________ > OpenSCAD mailing list > Discuss@lists.openscad.org > http://lists.openscad.org/mailman/listinfo/discuss_lists.openscad.org >