view runtime/doc/userfunc.txt @ 32936:c517845bd10e v9.0.1776

patch 9.0.1776: No support for stable Python 3 ABI Commit: https://github.com/vim/vim/commit/c13b3d1350b60b94fe87f0761ea31c0e7fb6ebf3 Author: Yee Cheng Chin <ychin.git@gmail.com> Date: Sun Aug 20 21:18:38 2023 +0200 patch 9.0.1776: No support for stable Python 3 ABI Problem: No support for stable Python 3 ABI Solution: Support Python 3 stable ABI Commits: 1) Support Python 3 stable ABI to allow mixed version interoperatbility Vim currently supports embedding Python for use with plugins, and the "dynamic" linking option allows the user to specify a locally installed version of Python by setting `pythonthreedll`. However, one caveat is that the Python 3 libs are not binary compatible across minor versions, and mixing versions can potentially be dangerous (e.g. let's say Vim was linked against the Python 3.10 SDK, but the user sets `pythonthreedll` to a 3.11 lib). Usually, nothing bad happens, but in theory this could lead to crashes, memory corruption, and other unpredictable behaviors. It's also difficult for the user to tell something is wrong because Vim has no way of reporting what Python 3 version Vim was linked with. For Vim installed via a package manager, this usually isn't an issue because all the dependencies would already be figured out. For prebuilt Vim binaries like MacVim (my motivation for working on this), AppImage, and Win32 installer this could potentially be an issue as usually a single binary is distributed. This is more tricky when a new Python version is released, as there's a chicken-and-egg issue with deciding what Python version to build against and hard to keep in sync when a new Python version just drops and we have a mix of users of different Python versions, and a user just blindly upgrading to a new Python could lead to bad interactions with Vim. Python 3 does have a solution for this problem: stable ABI / limited API (see https://docs.python.org/3/c-api/stable.html). The C SDK limits the API to a set of functions that are promised to be stable across versions. This pull request adds an ifdef config that allows us to turn it on when building Vim. Vim binaries built with this option should be safe to freely link with any Python 3 libraies without having the constraint of having to use the same minor version. Note: Python 2 has no such concept and this doesn't change how Python 2 integration works (not that there is going to be a new version of Python 2 that would cause compatibility issues in the future anyway). --- Technical details: ====== The stable ABI can be accessed when we compile with the Python 3 limited API (by defining `Py_LIMITED_API`). The Python 3 code (in `if_python3.c` and `if_py_both.h`) would now handle this and switch to limited API mode. Without it set, Vim will still use the full API as before so this is an opt-in change. The main difference is that `PyType_Object` is now an opaque struct that we can't directly create "static types" out of, and we have to create type objects as "heap types" instead. This is because the struct is not stable and changes from version to version (e.g. 3.8 added a `tp_vectorcall` field to it). I had to change all the types to be allocated on the heap instead with just a pointer to them. Other functions are also simply missing in limited API, or they are introduced too late (e.g. `PyUnicode_AsUTF8AndSize` in 3.10) to it that we need some other ways to do the same thing, so I had to abstract a few things into macros, and sometimes re-implement functions like `PyObject_NEW`. One caveat is that in limited API, `OutputType` (used for replacing `sys.stdout`) no longer inherits from `PyStdPrinter_Type` which I don't think has any real issue other than minor differences in how they convert to a string and missing a couple functions like `mode()` and `fileno()`. Also fixed an existing bug where `tp_basicsize` was set incorrectly for `BufferObject`, `TabListObject, `WinListObject`. Technically, there could be a small performance drop, there is a little more indirection with accessing type objects, and some APIs like `PyUnicode_AsUTF8AndSize` are missing, but in practice I didn't see any difference, and any well-written Python plugin should try to avoid excessing callbacks to the `vim` module in Python anyway. I only tested limited API mode down to Python 3.7, which seemes to compile and work fine. I haven't tried earlier Python versions. 2) Fix PyIter_Check on older Python vers / type##Ptr unused warning For PyIter_Check, older versions exposed them as either macros (used in full API), or a function (for use in limited API). A previous change exposed PyIter_Check to the dynamic build because Python just moved it to function-only in 3.10 anyway. Because of that, just make sure we always grab the function in dynamic builds in earlier versions since that's what Python eventually did anyway. 3) Move Py_LIMITED_API define to configure script Can now use --with-python-stable-abi flag to customize what stable ABI version to target. Can also use an env var to do so as well. 4) Show +python/dyn-stable in :version, and allow has() feature query Not sure if the "/dyn-stable" suffix would break things, or whether we should do it another way. Or just don't show it in version and rely on has() feature checking. 5) Documentation first draft. Still need to implement v:python3_version 6) Fix PyIter_Check build breaks when compiling against Python 3.8 7) Add CI coverage stable ABI on Linux/Windows / make configurable on Windows This adds configurable options for Windows make files (both MinGW and MSVC). CI will also now exercise both traditional full API and stable ABI for Linux and Windows in the matrix for coverage. Also added a "dynamic" option to Linux matrix as a drive-by change to make other scripting languages like Ruby / Perl testable under both static and dynamic builds. 8) Fix inaccuracy in Windows docs Python's own docs are confusing but you don't actually want to use `python3.dll` for the dynamic linkage. 9) Add generated autoconf file 10) Add v:python3_version support This variable indicates the version of Python3 that Vim was built against (PY_VERSION_HEX), and will be useful to check whether the Python library you are loading in dynamically actually fits it. When built with stable ABI, it will be the limited ABI version instead (`Py_LIMITED_API`), which indicates the minimum version of Python 3 the user should have, rather than the exact match. When stable ABI is used, we won't be exposing PY_VERSION_HEX in this var because it just doesn't seem necessary to do so (the whole point of stable ABI is the promise that it will work across versions), and I don't want to confuse the user with too many variables. Also, cleaned up some documentation, and added help tags. 11) Fix Python 3.7 compat issues Fix a couple issues when using limited API < 3.8 - Crash on exit: In Python 3.7, if a heap-allocated type is destroyed before all instances are, it would cause a crash later. This happens when we destroyed `OptionsType` before calling `Py_Finalize` when using the limited API. To make it worse, later versions changed the semantics and now each instance has a strong reference to its own type and the recommendation has changed to have each instance de-ref its own type and have its type in GC traversal. To avoid dealing with these cross-version variations, we just don't free the heap type. They are static types in non-limited-API anyway and are designed to last through the entirety of the app, and we also don't restart the Python runtime and therefore do not need it to have absolutely 0 leaks. See: - https://docs.python.org/3/whatsnew/3.8.html#changes-in-the-c-api - https://docs.python.org/3/whatsnew/3.9.html#changes-in-the-c-api - PyIter_Check: This function is not provided in limited APIs older than 3.8. Previously I was trying to mock it out using manual PyType_GetSlot() but it was brittle and also does not actually work properly for static types (it will generate a Python error). Just return false. It does mean using limited API < 3.8 is not recommended as you lose the functionality to handle iterators, but from playing with plugins I couldn't find it to be an issue. - Fix loading of PyIter_Check so it will be done when limited API < 3.8. Otherwise loading a 3.7 Python lib will fail even if limited API was specified to use it. 12) Make sure to only load `PyUnicode_AsUTF8AndSize` in needed in limited API We don't use this function unless limited API >= 3.10, but we were loading it regardless. Usually it's ok in Unix-like systems where Python just has a single lib that we load from, but in Windows where there is a separate python3.dll this would not work as the symbol would not have been exposed in this more limited DLL file. This makes it much clearer under what condition is this function needed. closes: #12032 Signed-off-by: Christian Brabandt <cb@256bit.org> Co-authored-by: Yee Cheng Chin <ychin.git@gmail.com>
author Christian Brabandt <cb@256bit.org>
date Sun, 20 Aug 2023 21:30:04 +0200
parents 695b50472e85
children 53416c49a7ab
line wrap: on
line source

*userfunc.txt*	For Vim version 9.0.  Last change: 2023 May 23


		  VIM REFERENCE MANUAL	  by Bram Moolenaar


Defining and using functions.

This is introduced in section |41.7| of the user manual.

1. Defining a function			|define-function|
2. Calling a function			|:call|
3. Cleaning up in a function		|:defer|
4. Automatically loading functions	|autoload-functions|

==============================================================================

1. Defining a function ~
						*define-function*
New functions can be defined.  These can be called just like builtin
functions.  The function executes a sequence of Ex commands.  Normal mode
commands can be executed with the |:normal| command.

The function name must start with an uppercase letter, to avoid confusion with
builtin functions.  To prevent from using the same name in different scripts
make them script-local.  If you do use a global function then avoid obvious,
short names.  A good habit is to start the function name with the name of the
script, e.g., "HTMLcolor()".

In legacy script it is also possible to use curly braces, see
|curly-braces-names|.

The |autoload| facility is useful to define a function only when it's called.

							*local-function*
A function local to a legacy script must start with "s:".  A local script
function can only be called from within the script and from functions, user
commands and autocommands defined in the script.  It is also possible to call
the function from a mapping defined in the script, but then |<SID>| must be
used instead of "s:" when the mapping is expanded outside of the script.
There are only script-local functions, no buffer-local or window-local
functions.

In |Vim9| script functions are local to the script by default, prefix "g:" to
define a global function.

				*:fu* *:function* *E128* *E129* *E123* *E454*
:fu[nction]		List all functions and their arguments.

:fu[nction] {name}	List function {name}.
			{name} can also be a |Dictionary| entry that is a
			|Funcref|: >
				:function dict.init
<			Note that {name} is not an expression, you cannot use
			a variable that is a function reference.  You can use
			this dirty trick to list the function referred to with
			variable "Funcref": >
				let g:MyFuncref = Funcref
				func g:MyFuncref
				unlet g:MyFuncref

:fu[nction] /{pattern}	List functions with a name matching {pattern}.
			Example that lists all functions ending with "File": >
				:function /File$
<
							*:function-verbose*
When 'verbose' is non-zero, listing a function will also display where it was
last defined. Example: >

    :verbose function SetFileTypeSH
	function SetFileTypeSH(name)
	    Last set from /usr/share/vim/vim-7.0/filetype.vim
<
See |:verbose-cmd| for more information.

						*E124* *E125* *E853* *E884*
:fu[nction][!] {name}([arguments]) [range] [abort] [dict] [closure]
			Define a new function by the name {name}.  The body of
			the function follows in the next lines, until the
			matching |:endfunction|.
								*E1267*
			The name must be made of alphanumeric characters and
			'_', and must start with a capital or "s:" (see
			above).  Note that using "b:" or "g:" is not allowed.
			(since patch 7.4.260 E884 is given if the function
			name has a colon in the name, e.g. for "foo:bar()".
			Before that patch no error was given).

			{name} can also be a |Dictionary| entry that is a
			|Funcref|: >
				:function dict.init(arg)
<			"dict" must be an existing dictionary.  The entry
			"init" is added if it didn't exist yet.  Otherwise [!]
			is required to overwrite an existing function.  The
			result is a |Funcref| to a numbered function.  The
			function can only be used with a |Funcref| and will be
			deleted if there are no more references to it.
								*E127* *E122*
			When a function by this name already exists and [!] is
			not used an error message is given.  There is one
			exception: When sourcing a script again, a function
			that was previously defined in that script will be
			silently replaced.
			When [!] is used, an existing function is silently
			replaced.  Unless it is currently being executed, that
			is an error.
			NOTE: Use ! wisely.  If used without care it can cause
			an existing function to be replaced unexpectedly,
			which is hard to debug.
			NOTE: In Vim9 script script-local functions cannot be
			deleted or redefined.

			For the {arguments} see |function-argument|.

					*:func-range* *a:firstline* *a:lastline*
			When the [range] argument is added, the function is
			expected to take care of a range itself.  The range is
			passed as "a:firstline" and "a:lastline".  If [range]
			is excluded, ":{range}call" will call the function for
			each line in the range, with the cursor on the start
			of each line.  See |function-range-example|.
			The cursor is still moved to the first line of the
			range, as is the case with all Ex commands.
								*:func-abort*
			When the [abort] argument is added, the function will
			abort as soon as an error is detected.
								*:func-dict*
			When the [dict] argument is added, the function must
			be invoked through an entry in a |Dictionary|.  The
			local variable "self" will then be set to the
			dictionary.  See |Dictionary-function|.
						*:func-closure* *E932*
			When the [closure] argument is added, the function
			can access variables and arguments from the outer
			scope.  This is usually called a closure.  In this
			example Bar() uses "x" from the scope of Foo().  It
			remains referenced even after Foo() returns: >
				:function! Foo()
				:  let x = 0
				:  function! Bar() closure
				:    let x += 1
				:    return x
				:  endfunction
				:  return funcref('Bar')
				:endfunction

				:let F = Foo()
				:echo F()
<				1 >
				:echo F()
<				2 >
				:echo F()
<				3

						*function-search-undo*
			The last used search pattern and the redo command "."
			will not be changed by the function.  This also
			implies that the effect of |:nohlsearch| is undone
			when the function returns.

			*:endf* *:endfunction* *E126* *E193* *W22* *E1151*
:endf[unction] [argument]
			The end of a function definition.  Best is to put it
			on a line by its own, without [argument].

			[argument] can be:
				| command	command to execute next
				\n command	command to execute next
				" comment	always ignored
				anything else	ignored, warning given when
						'verbose' is non-zero
			The support for a following command was added in Vim
			8.0.0654, before that any argument was silently
			ignored.

			To be able to define a function inside an `:execute`
			command, use line breaks instead of |:bar|: >
				:exe "func Foo()\necho 'foo'\nendfunc"
<
				*:delf* *:delfunction* *E131* *E933* *E1084*
:delf[unction][!] {name}
			Delete function {name}.
			{name} can also be a |Dictionary| entry that is a
			|Funcref|: >
				:delfunc dict.init
<			This will remove the "init" entry from "dict".  The
			function is deleted if there are no more references to
			it.
			With the ! there is no error if the function does not
			exist.
							*:retu* *:return* *E133*
:retu[rn] [expr]	Return from a function.  When "[expr]" is given, it is
			evaluated and returned as the result of the function.
			If "[expr]" is not given, the number 0 is returned.
			When a function ends without an explicit ":return",
			the number 0 is returned.

			In a :def function *E1095* is given if unreachable
			code follows after the `:return`.
			In legacy script there is no check for unreachable
			lines, thus there is no warning if commands follow
			`:return`.  Also, there is no check if the following
			line contains a valid command.  Forgetting the line
			continuation backslash may go unnoticed: >
				return 'some text'
				       .. ' some more text'
<			Will happily return "some text" without an error.  It
			should have been: >
				return 'some text'
				       \ .. ' some more text'
<
			If the ":return" is used after a |:try| but before the
			matching |:finally| (if present), the commands
			following the ":finally" up to the matching |:endtry|
			are executed first.  This process applies to all
			nested ":try"s inside the function.  The function
			returns at the outermost ":endtry".

						*function-argument* *a:var*
An argument can be defined by giving its name.  In the function this can then
be used as "a:name" ("a:" for argument) (in a `:def` function "a:" is not
used).
					*a:0* *a:1* *a:000* *E740* *...*
Up to 20 arguments can be given, separated by commas.  After the named
arguments an argument "..." can be specified, which means that more arguments
may optionally be following.  In the function the extra arguments can be used
as "a:1", "a:2", etc.  "a:0" is set to the number of extra arguments (which
can be 0).  "a:000" is set to a |List| that contains these arguments.  Note
that "a:1" is the same as "a:000[0]".
							*E742* *E1090*
The a: scope and the variables in it cannot be changed, they are fixed.
However, if a composite type is used, such as |List| or |Dictionary| , you can
change their contents.  Thus you can pass a |List| to a function and have the
function add an item to it.  If you want to make sure the function cannot
change a |List| or |Dictionary| use |:lockvar|.

It is also possible to define a function without any arguments.  You must
still supply the () then.

It is allowed to define another function inside a function body.

						*optional-function-argument*
You can provide default values for positional named arguments.  This makes
them optional for function calls.  When a positional argument is not
specified at a call, the default expression is used to initialize it.
This only works for functions declared with `:function` or `:def`, not for
lambda expressions |expr-lambda|.

Example: >
  function Something(key, value = 10)
     echo a:key .. ": " .. a:value
  endfunction
  call Something('empty')	"empty: 10"
  call Something('key', 20)	"key: 20"

The argument default expressions are evaluated at the time of the function
call, not when the function is defined.  Thus it is possible to use an
expression which is invalid the moment the function is defined.  The
expressions are also only evaluated when arguments are not specified during a
call.
						*none-function_argument*
You can pass |v:none| to use the default expression.  Note that this means you
cannot pass v:none as an ordinary value when an argument has a default
expression.

Example: >
  function Something(a = 10, b = 20, c = 30)
  endfunction
  call Something(1, v:none, 3)	    " b = 20
<
								*E989*
Optional arguments with default expressions must occur after any mandatory
arguments.  You can use "..." after all optional named arguments.

It is possible for later argument defaults to refer to prior arguments,
but not the other way around.  They must be prefixed with "a:", as with all
arguments.

Example that works: >
  :function Okay(mandatory, optional = a:mandatory)
  :endfunction
Example that does NOT work: >
  :function NoGood(first = a:second, second = 10)
  :endfunction
<
When not using "...", the number of arguments in a function call must be at
least equal to the number of mandatory named arguments.  When using "...", the
number of arguments may be larger than the total of mandatory and optional
arguments.

							*local-variables*
Inside a function local variables can be used.  These will disappear when the
function returns.  Global variables need to be accessed with "g:".
Inside functions local variables are accessed without prepending anything.
But you can also prepend "l:" if you like.  This is required for some reserved
names, such as "count".

Example: >
  :function Table(title, ...)
  :  echohl Title
  :  echo a:title
  :  echohl None
  :  echo a:0 .. " items:"
  :  for s in a:000
  :    echon ' ' .. s
  :  endfor
  :endfunction

This function can then be called with: >
  call Table("Table", "line1", "line2")
  call Table("Empty Table")

To return more than one value, return a |List|: >
  :function Compute(n1, n2)
  :  if a:n2 == 0
  :    return ["fail", 0]
  :  endif
  :  return ["ok", a:n1 / a:n2]
  :endfunction

This function can then be called with: >
  :let [success, div] = Compute(102, 6)
  :if success == "ok"
  :  echo div
  :endif
<
==============================================================================

2. Calling a function ~
						*:cal* *:call* *E107*
:[range]cal[l] {name}([arguments])
		Call a function.  The name of the function and its arguments
		are as specified with `:function`.  Up to 20 arguments can be
		used.  The returned value is discarded.
		In |Vim9| script using `:call` is optional, these two lines do
		the same thing: >
			call SomeFunc(arg)
			SomeFunc(arg)
<		Without a range and for functions that accept a range, the
		function is called once.  When a range is given the cursor is
		positioned at the start of the first line before executing the
		function.
		When a range is given and the function doesn't handle it
		itself, the function is executed for each line in the range,
		with the cursor in the first column of that line.  The cursor
		is left at the last line (possibly moved by the last function
		call).  The arguments are re-evaluated for each line.  Thus
		this works:
						*function-range-example*  >
	:function Mynumber(arg)
	:  echo line(".") .. " " .. a:arg
	:endfunction
	:1,5call Mynumber(getline("."))
<
		The "a:firstline" and "a:lastline" are defined anyway, they
		can be used to do something different at the start or end of
		the range.

		Example of a function that handles the range itself: >

	:function Cont() range
	:  execute (a:firstline + 1) .. "," .. a:lastline .. 's/^/\t\\ '
	:endfunction
	:4,8call Cont()
<
		This function inserts the continuation character "\" in front
		of all the lines in the range, except the first one.

		When the function returns a composite value it can be further
		dereferenced, but the range will not be used then.  Example: >
	:4,8call GetDict().method()
<		Here GetDict() gets the range but method() does not.

								*E117*
When a function cannot be found the error "E117: Unknown function" will be
given.  If the function was using an autoload path or an autoload import and
the script is a |Vim9| script, this may also be caused by the function not
being exported.

								*E132*
The recursiveness of user functions is restricted with the |'maxfuncdepth'|
option.

It is also possible to use `:eval`.  It does not support a range, but does
allow for method chaining, e.g.: >
	eval GetList()->Filter()->append('$')

A function can also be called as part of evaluating an expression or when it
is used as a method: >
	let x = GetList()
	let y = GetList()->Filter()

==============================================================================

3. Cleaning up in a function ~
							*:defer*
:defer {func}({args})	Call {func} when the current function is done.
			{args} are evaluated here.

Quite often a command in a function has a global effect, which must be undone
when the function finishes.  Handling this in all kinds of situations can be a
hassle.  Especially when an unexpected error is encountered.  This can be done
with `try` / `finally` blocks, but this gets complicated when there is more
than one.

A much simpler solution is using `defer`.  It schedules a function call when
the function is returning, no matter if there is an error.  Example: >
	func Filter(text) abort
	  call writefile(a:text, 'Tempfile')
	  call system('filter < Tempfile > Outfile')
	  call Handle('Outfile')
	  call delete('Tempfile')
	  call delete('Outfile')
	endfunc

Here 'Tempfile' and 'Outfile' will not be deleted if something causes the
function to abort.  `:defer` can be used to avoid that: >
	func Filter(text) abort
	  call writefile(a:text, 'Tempfile')
	  defer delete('Tempfile')
	  defer delete('Outfile')
	  call system('filter < Tempfile > Outfile')
	  call Handle('Outfile')
	endfunc

Note that deleting "Outfile" is scheduled before calling `system()`, since it
can be created even when `system()` fails.

The deferred functions are called in reverse order, the last one added is
executed first.  A useless example: >
	func Useless() abort
	  for s in range(3)
	    defer execute('echomsg "number ' .. s .. '"')
	  endfor
	endfunc

Now `:messages` shows:
	number 2
	number 1
	number 0

Any return value of the deferred function is discarded.  The function cannot
be followed by anything, such as "->func" or ".member".  Currently `:defer
GetArg()->TheFunc()` does not work, it may work in a later version.

Errors are reported but do not cause aborting execution of deferred functions.

No range is accepted.  The function can be a partial with extra arguments, but
not with a dictionary. *E1300*

==============================================================================

4. Automatically loading functions ~
							*autoload-functions*
When using many or large functions, it's possible to automatically define them
only when they are used.  There are two methods: with an autocommand and with
the "autoload" directory in 'runtimepath'.

In |Vim9| script there is also an autoload mechanism for imported scripts, see
|import-autoload|.


Using an autocommand ~

This is introduced in the user manual, section |51.4|.

The autocommand is useful if you have a plugin that is a long Vim script file.
You can define the autocommand and quickly quit the script with `:finish`.
That makes Vim startup faster.  The autocommand should then load the same file
again, setting a variable to skip the `:finish` command.

Use the FuncUndefined autocommand event with a pattern that matches the
function(s) to be defined.  Example: >

	:au FuncUndefined BufNet* source ~/vim/bufnetfuncs.vim

The file "~/vim/bufnetfuncs.vim" should then define functions that start with
"BufNet".  Also see |FuncUndefined|.


Using an autoload script ~
							*autoload* *E746*
This is introduced in the user manual, section |52.2|.

Using a script in the "autoload" directory is simpler, but requires using
exactly the right file name.  A function that can be autoloaded has a name
like this: >

	:call filename#funcname()

These functions are always global, in Vim9 script "g:" needs to be used: >
	:call g:filename#funcname()

When such a function is called, and it is not defined yet, Vim will search the
"autoload" directories in 'runtimepath' for a script file called
"filename.vim".  For example "~/.vim/autoload/filename.vim".  That file should
then define the function like this: >

	function filename#funcname()
	   echo "Done!"
	endfunction

If the file doesn't exist, Vim will also search in 'packpath' (under "start")
to allow calling packages' functions from your .vimrc when the packages have
not been added to 'runtimepath' yet (see |packages|).

The file name and the name used before the # in the function must match
exactly, and the defined function must have the name exactly as it will be
called.  In Vim9 script the "g:" prefix must be used: >
	function g:filename#funcname()

or for a compiled function: >
	def g:filename#funcname()

It is possible to use subdirectories.  Every # in the function name works like
a path separator.  Thus when calling a function: >

	:call foo#bar#func()

Vim will look for the file "autoload/foo/bar.vim" in 'runtimepath'.

This also works when reading a variable that has not been set yet: >

	:let l = foo#bar#lvar

However, when the autoload script was already loaded it won't be loaded again
for an unknown variable.

When assigning a value to such a variable nothing special happens.  This can
be used to pass settings to the autoload script before it's loaded: >

	:let foo#bar#toggle = 1
	:call foo#bar#func()

Note that when you make a mistake and call a function that is supposed to be
defined in an autoload script, but the script doesn't actually define the
function, you will get an error message for the missing function.  If you fix
the autoload script it won't be automatically loaded again.  Either restart
Vim or manually source the script.

Also note that if you have two script files, and one calls a function in the
other and vice versa, before the used function is defined, it won't work.
Avoid using the autoload functionality at the toplevel.

In |Vim9| script you will get error *E1263* if you define a function with
a "#" character in the name.  You should use a name without "#" and use
`:export`.

Hint: If you distribute a bunch of scripts you can pack them together with the
|vimball| utility.  Also read the user manual |distribute-script|.


 vim:tw=78:ts=8:noet:ft=help:norl: