3

If I source:

let Mydict = { 'data': [0, 1, 2, 3] }
fu! Mydict.mylen()
    return len(self.data)
endfu

Then, I can execute echo Mydict.mylen() which returns 4 because it's the length of the list [0,1,2,3]. I didn't have to give the dict attribute to the function Mydict.mylen().


If I source:

fu! MyFunc() dict
    return len(self.data)
endfu
let mydict = { 'data': [0, 1, 2, 3], 'mylen': function('MyFunc') }

Then, I can execute echo mydict.mylen() which, again, returns 4, for the same reason as before. However, this time, I had to give the dict attribute to the function MyFunc(). Without dict, it would have raised the errors:

E121: Undefined variable: self
E116: Invalid arguments for function len(self.data)
E15: Invalid expression: len(self.data)

If I source:

fu! Order() dict
    echo 'eat your ' . self.name
endfu
let food       = { 'name': 'vegetables' }
let BuildOrder = function('Order', food)

Then, I can execute call BuildOrder(), which displays eat your vegetables. I had to give the dict attribute to the function Order(), for the same reason as before.


If I source:

fu! Describe(count, adj) dict
    echo a:count.' '.a:adj.' '. self.name
endfu
let animal      = { 'name': 'piggies' }
let Description = function('Describe', [ 3 ], animal)

Then, I can execute call Description('little'), which displays 3 little piggies. And again, I had to give the dict attribute to the Describe() function.


dict is only needed in the last 3 of the 4 previous snippets. What does Vim do internally, which explains that dict is not needed in the first one, but is in all the others?

And whatever it does, why doesn't it do it in the last 3 snippets? What would happen if it did it all the time, or never?

5

This is described at :help Dictionary-function:

                *Dictionary-function* *self* *E725* *E862*
When a function is defined with the "dict" attribute it can be used in a
special way with a dictionary.  Example: >
    :function Mylen() dict
    :   return len(self.data)
    :endfunction
    :let mydict = {'data': [0, 1, 2, 3], 'len': function("Mylen")}
    :echo mydict.len()

This is like a method in object oriented programming.  The entry in the
Dictionary is a |Funcref|.  The local variable "self" refers to the dictionary
the function was invoked from.

It is also possible to add a function without the "dict" attribute as a
Funcref to a Dictionary, but the "self" variable is not available then.

                *numbered-function* *anonymous-function*
To avoid the extra name for the function it can be defined and directly
assigned to a Dictionary in this way: >
    :let mydict = {'data': [0, 1, 2, 3]}
    :function mydict.len()
    :   return len(self.data)
    :endfunction
    :echo mydict.len()

The function will then get a number and the value of dict.len is a |Funcref|
that references this function.  The function can only be used through a
|Funcref|.  It will automatically be deleted when there is no |Funcref|
remaining that refers to it.

Both approaches define a function which will have access to their containing dict via the name self.

The function mydict.len approach is just syntactic sugar to define the functions directly in the dictionary. You can still assign that function to other dictionaries:

:let otherdict = { 'data': [0, 1], 'len': function(mydict.len) }
:echo otherdict.len()
2
| improve this answer | |

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.