35

I want to make a function that has optional arguments.

In python I would do something like this:

def functionName(arg1,arg2=false,arg3=false):
    if arg2:
        #Do stuff with arguments
    else:
        #Do stuff without arguments

I have tried doing function FunctionName(arg1,arg2=false,arg3=false), but it just gives me a error saying invalid argument.

How would I do this in vimscript?

36

Yes, you can take optional arguments in a function. It is not as convenient as python's way of doing it, but this is how you do it:

function FooBar(...) " This is like *args in python
    echom a:0 " a:0 contains an integer which is the number of arguments passed to the function
    echom a:1 " a:1 contains the first argument passed, a:2 contains the second and so on
    echo a:000 " a:000 contains a list of all arguments that were passed to the function
endfunction

Note that you may only have up to 20 arguments in this fashion.

Relevant help topics:

:help :function
:help function-argument
26

Late to the party a bit but I didn't see my favorite one:

function! FunctionName(arg1,...)
    let arg2 = get(a:, 1, 0)
    let arg3 = get(a:, 2, 0)

    if arg2
        "Do stuff with arguments"
    else
        "Do stuff without arguments"
    endif
endfunction

in which get(a:, n, default) will get the nth optional argument returning default if it's not present.

  • Oooh that's nice! – joeytwiddle Sep 6 '17 at 1:57
  • 3
    I know this is super old, but just FYI to anyone reading this. You cannot do let a:arg= anymore in vim. You must use something like let l:arg= or just let arg=. See github.com/vim/vim/commit/… – jmzagorski Feb 21 at 18:37
22

This pattern will let you assign meaningful names to each argument, and provide a default value for any arguments that were not provided:

function FunctionName(foo, ...)
  let bar = a:0 >= 1 ? a:1 : 0
  let baz = a:0 >= 2 ? a:2 : 0
  ...
  " Code that makes use of a:foo, bar and baz

As pointed out by Boris Brodski:

a:0 counts the number of optional arguments passed

a:1, a:2, ... let us access the optional arguments

The mandatory arguments (just foo in the example above) are not counted

condition ? result_if_true : result_if_false is the conditional (ternary) expression, which evaluates to the second or third term depending on whether the first term was true or not.

So if no third argument is provided, baz will take the default value of 0.

One concern with the above example is that a:foo can only be accessed with the a: prefix, whilst bar and baz can do without a prefix. Since this is not very consistent, you may prefer to pull out all of the arguments into local variables, like so:

function FunctionName(...)
  let foo = a:1                  " Will throw an error if no arg was provided
  let bar = a:0 >= 2 ? a:2 : 0
  let baz = a:0 >= 3 ? a:3 : 0
  ...
  " Code that makes use of foo, bar and baz

(Technically, you can use the l: prefix to refer to local variables inside a function, for example l:baz, but this is redundant so I would not recommend it.)


But I do recommend that you use this form whenever possible:

function! s:FunctionName(...)

The ! allows you to redefine your function at runtime (e.g. by reloading the script), and the s: limits the function to script scope. That avoids polluting the global namespace (and risking collision) if your function is only referenced from elsewhere inside the script. It is generally the preferred way to define functions when they do not need to be globally visible. ;-)

  • a:0 doesn't include the fixed named parameters. a:1 is the first parameter within the ... (Just tested with VIM 8.0) – Boris Brodski Apr 30 '18 at 11:54
  • Thanks @BorisBrodski you're right, good catch. I have corrected the answer. – joeytwiddle May 1 '18 at 14:44
8

I'm not well versed in vimscript, but this is how I would do it:

function Func(foo, ...)
  if a:0 < 1
    let bar = "Unspecified bar"
  else
    let bar = a:1
  endif
  if a:0 < 2
    let baz = "Unspecified baz"
  else
    let baz = a:2
  endif

  echo a:foo
  echo bar
  echo baz
endfunction

You can then call Func("Hello", "World"), and see that it prints "Hello", "World", "Unspecified baz".

This is using the varargs feature of vim functions, which lets you pass an arbitrary number of extra arguments to the function. The arguments are stored in variables which, depending on a:0 (the length of the extra arguments list), either get set to their corresponding argument or a default value.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.