discuss@lists.openscad.org

OpenSCAD general discussion Mailing-list

View all threads

Default parameter sample

JW
Jim Witte
Fri, Mar 25, 2022 5:49 PM

I needed to do default parameters that defaulted to other parameters,
like a function doRender(color, colorTop, colorBottom) where "colorTop" and
"colorBottom" default to "color" if not specified)

I found this that uses an inner helper function
[
https://iamwilchung.wordpress.com/2012/02/08/how-to-write-modules-with-fallback-default-arguments-in-openscad/
]

But it seemed unwieldy.  So I came up with this:

module defaultParams(x = 100, y = "undef", z = "undef") {
xi = x;                                // "x internal"
yi = (y == "undef") ? xi : y;
zi = (z == "undef") ? xi : z;
echo(xi, ,yi, zi);
}  // defaultParams

// ** Case 1:  All params
// -> "2, 3, 4"
defaultParams(x=2, y=3, z=4);

// ** Case 2: Only x
// -> "2, 2, 2"
defaultParams(x=2);

// ** Case 3:  X and Y
// -> "2, 3, 2"
defaultParams(x=2, y=3);

// ** Case 4:  X and Z
// -> "2, 2, 4"
defaultParams(x=2, z=4);

// ** Case 5:  None (all default to 100)
// -> "100, 100, 100"
defaultParams();

// ** Case 6: Only z (x and y default to 100
// -> "100, 100, 9"
defaultParams(z = 9);

I needed to do default parameters that defaulted to other parameters, like a function doRender(color, colorTop, colorBottom) where "colorTop" and "colorBottom" default to "color" if not specified) I found this that uses an inner helper function [ https://iamwilchung.wordpress.com/2012/02/08/how-to-write-modules-with-fallback-default-arguments-in-openscad/ ] But it seemed unwieldy. So I came up with this: module defaultParams(x = 100, y = "undef", z = "undef") { xi = x; // "x internal" yi = (y == "undef") ? xi : y; zi = (z == "undef") ? xi : z; echo(xi, ,yi, zi); } // defaultParams // ** Case 1: All params // -> "2, 3, 4" defaultParams(x=2, y=3, z=4); // ** Case 2: Only x // -> "2, 2, 2" defaultParams(x=2); // ** Case 3: X and Y // -> "2, 3, 2" defaultParams(x=2, y=3); // ** Case 4: X and Z // -> "2, 2, 4" defaultParams(x=2, z=4); // ** Case 5: None (all default to 100) // -> "100, 100, 100" defaultParams(); // ** Case 6: Only z (x and y default to 100 // -> "100, 100, 9" defaultParams(z = 9);
JB
Jordan Brown
Fri, Mar 25, 2022 6:51 PM

On 3/25/2022 10:49 AM, Jim Witte wrote:

  I needed to do default parameters that defaulted to other
parameters, like a function doRender(color, colorTop, colorBottom)
where "colorTop" and "colorBottom" default to "color" if not specified)

I use this function a lot:

function default(val, def) = is_undef(val) ? def : val;

and then I would do your module like so:

module doRender(color, colorTop, colorBottom) {
    colorTop = default(colorTop, color);
    colorBottom = default(colorBottom, color);
    ...
}

On its face you might think this violates the "can't change the value of
a variable" rule, and it comes close.  However, you are allowed to
change a value - actually, to create a new variable - inside a separate
scope, and the body of the module is a separate scope from the
arguments, and the outer definition is visible until you're done with
the inner definition, so it works.  But if it makes you nervous, you
could name the inner variables _colorTop and _colorBottom or something
like that so that they are different.

Note that this uses the fact that unspecified arguments get the special
value undef.  That undef might come from the argument being not
specified in the call to doRender, or it could be explicitly undef in
that call, or it could (recursively) be missing from a higher-level
call.  Net, it works out to be pretty convenient.

On 3/25/2022 10:49 AM, Jim Witte wrote: >   I needed to do default parameters that defaulted to other > parameters, like a function doRender(color, colorTop, colorBottom) > where "colorTop" and "colorBottom" default to "color" if not specified) I use this function a lot: function default(val, def) = is_undef(val) ? def : val; and then I would do your module like so: module doRender(color, colorTop, colorBottom) { colorTop = default(colorTop, color); colorBottom = default(colorBottom, color); ... } On its face you might think this violates the "can't change the value of a variable" rule, and it comes close.  However, you *are* allowed to change a value - actually, to create a new variable - inside a separate scope, and the body of the module is a separate scope from the arguments, and the outer definition is visible until you're done with the inner definition, so it works.  But if it makes you nervous, you could name the inner variables _colorTop and _colorBottom or something like that so that they are different. Note that this uses the fact that unspecified arguments get the special value undef.  That undef might come from the argument being not specified in the call to doRender, or it could be explicitly undef in that call, or it could (recursively) be missing from a higher-level call.  Net, it works out to be pretty convenient.