Search code examples
functionmatlabexistsnot-exists

MATLAB Check Existence of Optional Parameters: not enough input arguments


I have written a Matlab R2020b function that optionally receives three inputs - but if the inputs are not received, they should be set to the defaults within the script.

function my_opt_func(opt1, opt2, opt3)
    if (~exist(opt1, 'var'))
        opt1 = setopt1();
    end
    if (~exist(opt2, 'var'))
        opt2 = setopt2();
    end
    if (~exist(opt3, 'var'))
        opt3 = setopt3();
    end

    disp(string(opt1) + string(opt2) + string(opt3))
    
    function opt1 = setopt1()
        opt1 = 1;
    end
    
    function opt2 = setopt2()
        opt2 = 2;
    end
    
    function opt3 = setopt3()
        opt3 = 3;
    end

end

Here, the different setopt functions are used to generate the appropriate default values.

Unfortunately, calling this function without parameters, as my_opt_func or my_opt_func() gives the error Not enough input arguments. I tried using a variant of varargin, but got the same error.

When I set the values without using the setopt functions, I don't get this error - but due to the complexity of my actual program, I really need to use functions to develop my defaults.

How do I fix this error so that the user can call the function with or without parameters - as either my_opt_func() or my_opt_func(param1, param2, param3)?


Solution

  • Cris answered your direct question in the commments, exist expects you to input the name of the variable, not the variable itself (since it might not exist!)

        if (~exist('opt1', 'var')) % <- char 'opt1' is the variable name
            opt1 = setopt1();
        end
    

    But there are some slightly nicer ways to do this anyway, the syntax for calling your function would be the same in all cases.

    1. Using nargin (number of arguments input). Since this is directly dependent on the number of input arguments, you can't do something like accidentally define the variable above your input validation and breaking the flow.
    function my_opt_func(opt1, opt2, opt3)
        if nargin < 1
            opt1 = setopt1();
        end
        if nargin < 2
            opt2 = setopt2();
        end
        if nargin < 3
            opt3 = setopt3();
        end
    
        ...
    
    1. Using the input parser with optional inputs and default values, in particular using addOptional means you can keep the function calling syntax the same. Alternatively you could use the input parser for name-value pairs. I find this is often overkill unless you want to utilise the other functionality inputParser offers.
    function my_opt_func(varargin)
        p = inputParser;
        p.addOptional( 'opt1', setopt1() );
        p.addOptional( 'opt2', setopt2() );
        p.addOptional( 'opt3', setopt3() );
        p.parse( varargin{:} );
    
        opt1 = p.Results.opt1;
        opt2 = p.Results.opt2;
        opt3 = p.Results.opt3;
    
        ...
    
    1. Since R2019b you can use the arguments syntax
    function my_opt_func(opt1, opt2, opt3)
        arguments
            opt1 double = setopt1()
            opt2 double = setopt2()
            opt3 double = setopt3()
        end
    
        ...
    

    Note that inputParser will run the setoptx functions for the default values regardless if values have been passed in, but the arguments syntax is more efficient since the setoptx functions will only be evaluated if the input isn't given.