# Basic proposal

There are a number of options and their attractiveness will depend on the scenario for their use, therefore it is difficult to make any broad recommendations of best practice.

I will say that generally it is not recommended to rely on global assignments as in your first example, because this method scales poorly and because it is easy to make mistakes and get invalid results.

One approach you might consider is this:

```
Options[defs] = {mu -> 1, sigma -> 1, lb -> 0, ub -> 10};
f[x_, OptionsPattern[defs]] :=
PDF[LogNormalDistribution[OptionValue[mu], OptionValue[sigma]], x]
```

Now you can call `f`

with one argument:

```
f[1.6]
```

```
0.216668
```

Or you can override values with explicit Options:

```
f[1.6, mu -> 1.7]
```

```
0.117023
```

You can also quickly change a value using `SetOptions`

:

```
SetOptions[defs, sigma -> 2]
```

```
{mu -> 1, sigma -> 2, lb -> 0, ub -> 10}
```

```
f[1.6]
```

```
0.120368
```

**Note:** making assignments to the Option names (e.g. `mu = 1`

) will break your code.

Consider either `Protect`

-ing these Symbols or using Strings instead, e.g. `"mu" -> 1`

.

One disadvantage of this method is that it lengthens definitions. Sometimes using `With`

makes these more clear:

```
f[x_, OptionsPattern[defs]] :=
With[{mu = OptionValue[mu], sigma = OptionValue[sigma]},
PDF[LogNormalDistribution[mu, sigma], x]
]
```

This can be streamlined using `listWith`

from: Constructing symbol definitions for With:

```
SetAttributes[listWith, HoldAll];
listWith[(set : Set | SetDelayed)[L_, R_], body_] :=
set @@@ Thread[Hold @@@ {L, R}, Hold] /. _[x__] :> With[{x}, body]
```

Now:

```
f[x_, OptionsPattern[defs]] :=
listWith[{mu, sigma} = OptionValue[{mu, sigma}],
PDF[LogNormalDistribution[mu, sigma], x]
]
```

# Automation

### Manual specification

Although this will not work with String parameter names here is a method to further automate function construction:

```
SetAttributes[defWithOpts, HoldAll]
defWithOpts[
sym_Symbol,
opts : {__Symbol},
(set : Set | SetDelayed)[h_[args___], RHS_]
] :=
set[
h[args, OptionsPattern[sym]],
listWith[opts = OptionValue[opts], RHS]
]
```

Now:

```
defWithOpts[def, {mu, sigma},
g[x_] := PDF[LogNormalDistribution[mu, sigma], x]
]
```

And the definition that was created:

```
?g
```

Global`g

```
g[x_, OptionsPattern[def]] :=
listWith[{mu, sigma} = OptionValue[{mu, sigma}],
PDF[LogNormalDistribution[mu, sigma], x]]
```

For code specific to String parameter names see: How to write complex function definitions at run time?

### Automatic detection

Yet another idea for automation, built on the assumption that you will first define the `Options`

list (with dummy values if necessary) *then* the functions. It works by finding all cases of parameter (Option) names within the right-hand-side of the definition.

```
SetAttributes[defAutoOpts, HoldAll]
defAutoOpts[
sym_Symbol: defs,
(set : Set | SetDelayed)[h_[args___], RHS_]
] :=
Cases[Unevaluated@RHS, Alternatives @@ Options[sym][[All, 1]], {-1}, Heads -> True] //
set[h[args, OptionsPattern[sym]], listWith[# = OptionValue[#], RHS]] &
```

Now you can do this:

```
defAutoOpts[
h[x_] := PDF[LogNormalDistribution[mu, sigma], x]
]
```

Which creates:

```
h[x_, OptionsPattern[defs]] :=
listWith[{mu, sigma} = OptionValue[{mu, sigma}],
PDF[LogNormalDistribution[mu, sigma], x]]
```

You can also call `defAutoOpts[defs2, . . .]`

to use a different parameter list.

I notice that you never Accepted an answer to this question. Does anything remain unaddressed or unsatisfactory? – Mr.Wizard – 2014-12-08T21:56:27.393