Quite often a script keeps state at the script level. That means using
script-local items. Until now these were kept in the "s:" dictionary.
As with function-local items, using a dictionary is slow. For Vim9
script we want to make it fast.
As before, when fixing performance we might as well fix some
Vim-specific "weirdness". No other language uses "s:" variables. And
the associated use of <SID> and <SNR>. Still, Vim needs them to avoid a
script putting everything in the global namespace.
Looking around in popular languages, it turns out that JavaScript had a
very similar problem: Everything went into the global namespace. Some
half-solutions with creating a new namespace were used, but eventually
in ES6 the import/export mechanism was introduced to do this properly.
This is also used by TypeScript.
It looks like using import and export statements works very well for Vim
script, and very similar to how it works for JavaScript. Basically, you
can write a Vim script just like before, except that all items at the
script level are script-local. Nothing goes into the global namespace.
Without any export, the script can be sourced, does its work, and leaves
no trace behind. Except when it explicitly uses "g:" to put something
in the global namespace or defines a user command.
Example script one.vim:
namespace
let cache = {}
export def GetItem(key: string): string
...
let result = get(cache, key, '')
if result == ''
result = ... lookup item
cache[key] = result
endif
return result
enddef
Example script two.vim:
import GetItem from './one.vim'
let item = GetItem(key)
Notice that "cache" remains local to one.vim. And in GetItem() it can
be located at compile time, thus during execution it can be accessed
fast, without computing a has of the key and doing a dictionary lookup.
In script two.vim only one specific item from one.vim is obtained.
"GetItem" is not defined in the global namespace.
When a plugin grows bigger it is convenient to split it up in multiple
files. Then each file will want to export some things, and keep other
things private. Also, it is possible to make a library, that exports a
well defined set of items, without polluting the global scope.
I'm currently experimenting with this:
- Use a "namespace" command at the top of the script to specify that
items at the script level are script-local.
- Use "import" commands to get functionality from other scripts.
- Use "export" commands to make functionality available to other
scripts.
For the performance part, a restriction will be that script-local items
are defined once and not deleted. That makes it possible to find them
by index, which is much faster than a dictionary lookup.
--
BEDEVERE: Stand by for attack!!
[CUT TO enormous army forming up. Trebuchets, rows of PIKEMEN, siege
towers, pennants flying, shouts of "Stand by for attack!" Traditional
army build-up shots. The shouts echo across the ranks of the army.
We see various groups reacting, and stirring themselves in readiness.]
ARTHUR: Who are they?
BEDEVERE: Oh, just some friends!
"Monty Python and the Holy Grail" PYTHON (MONTY) PICTURES LTD
/// Bram Moolenaar -- Br...@Moolenaar.net --
http://www.Moolenaar.net \\\
/// sponsor Vim, vote for features --
http://www.Vim.org/sponsor/ \\\
\\\ an exciting new programming language --
http://www.Zimbu.org ///
\\\ help me help AIDS victims --
http://ICCF-Holland.org ///