3

I posted this question on stackoverflow already, but realized afterwards that it's probably better to ask here.

So I have a function of the following form:

function! s:my_function(dict_arg)
    let darg = copy(a:dict_arg)

    func! my_inner_func(cond)
        if a:cond ==# 'a'
            execute darg.a
        elseif a:cond ==# 'b'
            execute darg.b
        elseif a:cond ==# 'c'
            execute darg.c
        endif
    endfunc

    return function('my_inner_func')
endfunc

Where the argument passed to the dict_arg parameter will be some dict keyed with a, b and c, with their respective values being strings representing Ex commands that will be executed depending on the specific cond (condition).

The purpose of the outer function s:my_function is to generate a Funcref that will execute the appropriate Ex command (darg.a, darg.b or darg.c) based on the cond, which is itself determined elsewhere by other variables.

So my problem is that I don't know how to reference the local variable darg defined in the scope of s:my_function from within my_inner_func. When the function is called, I get the error E121: Undefined variable: darg. It also doesn't work (same error) if I don't define the local variable darg, and instead just try to do execute a:dict_arg.b for instance.

I can get around it by defining darg to be global, as in let g:darg = copy(a:dict_arg), then later doing execute g:darg.a. But of course, I'd like to avoid that.

In something like Python, this type of lexical scope resolution is automatic. But VimL is well.. VimL. Any help or pointers will be appreciated.

New contributor
Jethro Cao is a new contributor to this site. Take care in asking for clarification, commenting, and answering. Check out our Code of Conduct.
5

I though it wasn't possible, but I was wrong.

See :h :func-closure

You need to patch two things:

  • add closure at the end of the inner of the function declaration
  • respect the usual naming conventions

For instance

function! s:my_function(dict_arg)
    let darg = copy(a:dict_arg)

    func! s:my_inner_func(cond) closure
      return darg[a:cond]
    endfunc

    return function('s:my_inner_func')
endfunc

let g:F = s:my_function({'a': 42, 'b': 5, 'c': 'str'})
  • Excellent! That was it. – Jethro Cao Nov 6 at 23:03

Your Answer

Jethro Cao is a new contributor. Be nice, and check out our Code of Conduct.

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.