I need to make a quick variation of a function. The calculation, or behaviour, differs slightly on the needs of the caller. I throw in a `bool`

parameter to do this switch. It’s fast and easy, yet I’m almost always disappointed later. It’s a bit hard to read from the call side. An enum, or distinct functions, would be cleaner.

### Setup

The basic example here is you have a function:

1 2 3 |
defn calc_formula = ( a : int, b : int )->(:float) { ... } |

And you have a new call-site that needs to slightly alter the behaviour. So you stick a boolean on to trigger that switch:

1 2 3 4 5 6 7 |
defn calc_formula = ( a : int, b : int, is_gain : bool )->(:float) { ... if (is_gain) { //something slightly different } ... } |

The function itself looks fine, but what happens to the caller?

1 |
var v = calc_formula( ia, ib, true ) |

When I’ve just modified the `calc_formula`

function then I’ll know what that `true`

means. But what happens when I come back months later. Or what if somebody else sees this code. They’ll have to flip to the function definition to understand the mysterious `true`

value. It’s not a typical parameter to this formula, thus it can’t be inferred from context.

### Enum

This looks easier to read:

1 |
var v = calc_formula( ia, ib, calc_formula_type.is_gain ) |

I can immediately see I’m using an `is_gain`

variant calculation. All I’ve done is swap out the boolean parameter for an enum.

1 2 3 4 5 6 7 8 |
enum calc_formula_type { standard is_gain } defn calc_formula = ( a : int, b : int, opt : calc_formula_type )->(:float) { ... } |

I’d like a language that can contextually resolve enums, so I can just type something like

`calc_formula( ia, ib, is_gain )`

. Having to remember the enum type names is kind of annoying. I’ll probably have some way to do this in Leaf.

### Distinct functions

An alternative is to use distinct function wrappers and hide the underlying function.

1 2 3 4 5 6 7 8 9 10 11 |
defn calc_formula = ( a : int, b : int ) -> { return calc_formula_impl(a,b,false) } defn calc_formula_is_gain = ( a : int, b : int ) -> { return calc_formula_impl(a,b,true) } defn calc_formula_impl = ( a : int, b : int, is_gain : bool ) -> { ... } |

The callers look good: `calc_formula(ia, ib)`

or `calc_formula_is_gain(ia, ib)`

. It still involves a boolean on the actual function implementation. Though it isn’t as bad since the only callers of the `calc_formula_impl`

know about it, and they’re defined right beside it. The context makes it easy to understand that the boolean parameter is.

### Deciding which to use

Both solutions make the calling code easier to understand.

The distinct functions form comes at the cost of boilerplate wrapper functions — I’m never a fan of boilerplate code. However, if the formula really is distinct, then it makes sense to have separate functions. If the two functions truly feel like two separate functions then I do prefer this form.

Consider for example `sin`

and `cos`

. They are basically the same function with a phase offset. I’d truly hate to see something like this in code:

1 |
var q = sin( angle, sin_mode.cos ) |

Sure, the implementation is nearly identical, but they feel like very distinct functions.

I also don’t like flags that change the purity of the function:

1 2 3 |
var bond = calc_bond( params ); var rbond = calc_bond( params, bond_mode.register_global ); |

The second form both calculates a bond and registers it in a global table, whereas the first bond is a clean function without any side effects.

That is, I put up with the boilerplate code if the flags approach “feels” wrong.

### Virtuals

If the function is a virtual member in a class I’ll nonetheless lean toward the flags approach. A series of functions can often place a burden on derived classes: the boilerplate multiplies.

A nice combined solution is to make a protected enum virtual and expose the wrapper functions in the base class.

1 2 3 4 5 6 7 8 9 10 11 |
class shape { defn calc_nominal_bounds = -> { return calc_bounds( bounds_type.nominal ) } defn calc_render_bounds = -> { return calc_bounds( bounds_type.render ) } protected abstract defn calc_bounds = ( how : bounds_type ) -> ( : rect ); } |

This lets me call the functions with the nice form `my_square.calc_render_bounds()`

but avoids having to overload multiple definitions in each derived class.