#Reducing boiler plate for functions with optional second argument

20 messages · Page 1 of 1 (latest)

worn bear
#

I have been writing some functions that are of the form set(key_part_1, key_part_2, value), where key_part_2 is optional and if unspecified has a default argument. I distinguish between whether key_part_2 is provided or not based on the number of arguments. So this ends up looking like:

function set(key_part_1, key_part_2, value);
function set(key_part_1, value);
function set(...args) {
  if (args.length == 3) ... get arg values ...
  else ... get arg values with default for key_part_2 ...
  ... logic ...
}

but this is a bit tedious to write many times. These are actually usually methods in classes, so I was thinking of using a decorator to try to automatically transform a version that takes all the arguments into one where the second argument is optional. But, it looks like the decorations cannot affect the signature of a method. Does anyone know of a clean way to do this?

It's possible that writing the overloaded functions every time is the cleanest way, I suppose.

#

it could also be that having optional arguments not at the end of the function is just a bad design, but it feels bad to me for the ordering to be key_part_1, value, key_part_2, or (slightly less bad, but still weird) for them to be value, key_part_1, key_part_2. Another option would be to make the key an object with multiple parts internally, but then every call to set requires constructing one of those objects

quasi spade
#

You can write a higher order function that returns set with overloads, but you are intending on using them as class methods so that would make them into properties which is pretty bad.

worn bear
#

Ah, can you say more about why it's bad for them to be properties? I don't have a strong grasp of the difference between methods and function-valued attributes

#

I guess they don't handle this the same way?

quasi spade
#

You can make them have this by using functions rather than arrow functions

#

Class methods exist on the prototype, while properties exist on every instance.

worn bear
#

ahh, I see

#

got it

quasi spade
#

Is this library code or application code?

worn bear
#

mmh, a small library that I'm planning to use in some games

#

writing the overloads and generic definition is an OK solution, it just feels a little tedious and I have a few places where this happens and I feel like it obscures the logic of what would otherwise be very simple functions

storm thornBOT
#
nonspicyburrito#0

Preview:```ts
type Args<K, V> =
| [key: K, value: V]
| [key1: K, key2: K, value: V]

function getArgs<K, V>(
args: Args<K, V>,
defaultKey2: K
) {
if (args.length === 3) return args
return [args[0], defaultKey2, args[1]]
}

function fn(...args: Args<string, number
...```

quasi spade
#

Here's how I would do it if you must stick to the signature.

worn bear
#

oh interesting

#

thanks, that is a nice solution!

#

I don't need to stick with the signature

#

but the alternatives feel clunky a bit to me

quasi spade
#

Ah, you should as const the return in L5, or annotate getArgs return type to be [K, K, V].

#

But yeah Args and getArgs are helpers you can reuse, so every implementation of fn is very simple with them.