# 1. Why using key=value syntax to manage input arguments is not a good idea

Abstract

The purpose of this example is to show why using the key=value syntax to provide optional arguments may be a poor programming practice. It can lead to difficulties to produce new releases of the software and can lead to difficult bugs. A safer approach, based on the empty matrix, is suggested.

## 1.1. The key=value syntax

In this section, we present a method to provide optional arguments based on the key=value syntax. This method makes use of the exists function. In the first part, we analyze the method to implement this syntax. In the second part, we analyse the benefits and the drawbacks of this method.

### 1.1.1. How to implement the key=value syntax

Consider the following simple function.

```function y = myfunction1 ( x, a, b, c )
y = a*x^2+b*x+c
endfunction```

It is straightforward to use this function:

```-->myfunction1 ( 1, 1, 3, 1)
ans  =
5.  ```

It may be more convenient if the arguments a, b and c were optional.

A method which seems to be interesting is the key=value syntax. In order to implement this method, we use the exists function. By default, the arguments a, b and c are all set to 1.

```function y = myfunction2 ( x, a, b, c )
if ~exists("a","local") then
a = 1
end
if ~exists("b","local") then
b = 1
end
if ~exists("c","local") then
c = 1
end
y = a*x^2+b*x+c
endfunction```

There are now several ways to call this function. We can call it without specifying the values of a, b or c, which are then set to their default values:

```-->myfunction2 ( 1 )
ans  =
3.  ```

In the previous example, the variable a, for example, is undefined when the body of the function myfunction2 is executed. Therefore, the statement exists("a","local") returns false, so that the associated if block is executed.

We can also specify just one argument, with the key=value syntax.

```-->myfunction2 ( 1, b=3 )
ans  =
5.  ```

In the previous example, the variable b is defined in the function myfunction2, so that the statement exists("b","local") returns true. Therefore, the associated if block is not executed: the value b=3 is then used, as expected. All in all, we set b, but skip a.

### 1.1.2. Benefits and drawbacks

The previous approach as several advantages:

• the method is simple to develop,
• we can skip arguments.

But there are also several significant drawbacks:

• We cannot change the name of the arguments. In all the future releases of this function (i.e. in the v2, v3, etc...), the optional arguments must be "a", "b" and "c". The developper cannot change this, without breaking the backward compatibility. Hence, if the developper poorly chose the name in the first release (i.e. v1), he cannot fix this in the later releases.
• This can lead to bugs, as we are going to see.

One possible bug is when the user uses a wrong variable name, which is ignored by the function.

```-->myfunction2 ( 1, d=3 )
ans  =
3.  ```

Here, the variable d is just ignored by the function, but the user does not get an error message: this silently fails. The previous example is simple, but suppose that the variable name is "H_form", but the user writes "Hform": would someone notice the bug ?

## 1.2. An implementation based on the empty matrix

In this section, we present a method to provide optional arguments which is both simple and safe. It is based on the varargin variable and the empty matrix.

The method that we suggest here is presented in more depth in [1].

We introduce the following function which is a simplified implementation of apifun_argindefault from the apifun module [2]. The function takes as input arguments the list of arguments vararglist, the variable index ivar and the default value default.

• If the argument ivar is not present in vararglist, it returns the default value.

• If the argument ivar is present in vararglist :
• if the argument is [], it returns the default value..

• else it returns vararglist(ivar).

```function argin = argindefault ( vararglist , ivar , default )
rhs = length(vararglist)
if ( rhs < ivar ) then
argin = default
else
if ( typeof(vararglist(ivar))== "constant" ) then
if ( vararglist(ivar) <> [] ) then
argin = vararglist(ivar)
else
argin = default
end
else
argin = vararglist(ivar)
end
end
endfunction```

We now define an implementation of the function which makes use of argindefault.

```function y = myfunction4 ( varargin )
[lhs,rhs]=argn();
if rhs<1 | rhs>3 then
lclmsg = "%s: Wrong number of input arguments: %d to %d expected.\n"
error(msprintf(gettext(lclmsg),"myfunction4",1,3));
end
x = varargin(1)
//
a = argindefault ( varargin , 2 , 1 )
b = argindefault ( varargin , 3 , 1 )
c = argindefault ( varargin , 4 , 1 )
//
y = a*x^2+b*x+c
endfunction```

The previous function has the following calling sequence:

``` y = myfunction4 ( x)
y = myfunction4 ( x, a)
y = myfunction4 ( x, a, b)
y = myfunction4 ( x, a, b, c)```

Moreover, any optional argument is replaced by its default value. The simplest example is with all optional arguments set to their default value:

```-->myfunction4 ( 1 )
ans  =
3.  ```

We can also set the argument b, and still use the default value of a.

```-->myfunction4 ( 1, [], 2)
ans  =
4.  ```

## 1.3. Conclusion

The key=value syntax is a simple method to provide optional arguments to a function. Still, it has several drawbacks which make it a difficult programming method.

On the other hand, the method based on varargin and the empty matrix is a safe programming practice. Although it is slighly more complicated at first glance, the argindefault function makes it as simple as the key=value syntax: but it is much safer.

There is a third method to manage optional, non-positional, input arguments. This method is based on (key,value) pairs. In the previous example, this method would manage the a, b, c options with the following statemements:

```y = myfunction4 ( x)
y = myfunction4 ( x, "a", a)
y = myfunction4 ( x, "b", b)
y = myfunction4 ( x, "a", a, "b", b)
y = myfunction4 ( x, "b", b, "a", a)```

With this method, the input arguments can be set without taking into account their position in the calling sequence. Moreover, the function can check that the key is within a pre-defined set of available options: this prevents for errors in the option names. An example of such a management in Scilab is the optimset/optimget function:

A script containing all the previous examples is provided here:

## 1.4. Acknowledgements

I thank Bruno PinĂ§on and Allan Cornet for their comments on this document.

2022-09-08 09:27