Rise, fellow VimLers and cease sobbing onto your consoles about the stink of
VimLPOO (VimL Programming Object Orientedly). Vim keeps an open mind and so
should you.
tl;dr : VimL OOP can haz class-reopening like Ruby
Okay, maybe not exactly like Ruby, but check it:
VimL’s OOP is more like javascript’s than Ruby’s. It doesn’t have explicit classes. It uses dictionaries to store data and methods that operate on it.
Here is one way in VimL to create an object factory:
As a quick recap, a Vim object is a dictionary with data and methods that can use the self. modifier internally to refer to its data and other methods. It turns out that Vim is not too particular about who gets to claim dict access on your objects. You’re free to create external functions, adorned with the dict modifier, and have them manipulate your objects as if they were created with the class originally:
This happens to be a script-local (s:) function; global scope would work too, but why pollute unnecessarily? Now, if you tried to do a naive direct call of this, you’d be sorely disappointed:
That makes sense… We created slapped() as a script-local function, not a method on the boy instance.
Happiness is just a call away:
:-D How cool is that?!
I have a little project in the works that uses this to allow clients of the engine to inject their own solutions to various parts of the workflow. It’s almost done, so I should be able to show something a bit more real-worldy soon. For now, what mischief can you concoct with this shiny new toy? I look forward to finding out. :-)
Vim on!
tl;dr : VimL OOP can haz class-reopening like Ruby
Okay, maybe not exactly like Ruby, but check it:
VimL’s OOP is more like javascript’s than Ruby’s. It doesn’t have explicit classes. It uses dictionaries to store data and methods that operate on it.
Here is one way in VimL to create an object factory:
function! Kid(name) <1> let k = {} <2> let k.name = a:name <3> func k.say(blah) dict <4> echo self.name . ': ' . a:blah endfunc return k <5> endfunction let boy = Kid('Jack') <6> let girl = Kid('Jill') call boy.say('wassup?') <7> call girl.say('chillin'' at the hill. u?') echo boy <8> |
Jack: wassup? Jill: chillin' at the hill. u? {'name': 'Jack', 'say': function('69')}
-
I like to use the full command form function when creating object factories (classes?).
-
The object container is a dictionary (hash).
-
You can explicitly set attributes outside of methods if desired.
-
I like to use the short command form func for methods. The dict argument tells Vim
that this is an instance method, providing us the self. accessor.
You don’t need the ! on method declarations as you do for the outer-level. -
The factory must return the newly created object.
-
Create an instance using the factory.
-
Call methods using dot notation.
-
The object in its native format is just a dictionary (hash).
function! RudeKid(name) let rk = Kid(a:name) <1> func! rk.say(blah) dict <2> echo self.name . ': Yo, biatch! ' . a:blah endfunc return rk endfunction let boy = RudeKid('Jack') let girl = Kid('Jill') call boy.say('wassup?') call girl.say('wtf?') echo boy |
Jack: Yo, biatch! wassup? Jill: wtf? {'name': 'Jack', 'say': function('72')}
-
Base this object on the parent factory.
-
Override methods as desired.
The use of ! is now required because the method already exists in the base object.
As a quick recap, a Vim object is a dictionary with data and methods that can use the self. modifier internally to refer to its data and other methods. It turns out that Vim is not too particular about who gets to claim dict access on your objects. You’re free to create external functions, adorned with the dict modifier, and have them manipulate your objects as if they were created with the class originally:
function! s:slapped() dict echo self.name . " just got slapped!" endfunction |
This happens to be a script-local (s:) function; global scope would work too, but why pollute unnecessarily? Now, if you tried to do a naive direct call of this, you’d be sorely disappointed:
call boy.slapped() |
Error detected while processing jack_and_jill.vim: Line 42: E716: Key not present in Dictionary: slapped
That makes sense… We created slapped() as a script-local function, not a method on the boy instance.
Adding the method to the Kid() factory after having created the boy instance would be just as useless. |
Happiness is just a call away:
call call('s:slapped', [], boy) " Jack just got slapped! |
:-D How cool is that?!
I have a little project in the works that uses this to allow clients of the engine to inject their own solutions to various parts of the workflow. It’s almost done, so I should be able to show something a bit more real-worldy soon. For now, what mischief can you concoct with this shiny new toy? I look forward to finding out. :-)
Vim on!