summaryrefslogtreecommitdiffstats
path: root/runtime/doc/vim9.txt
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:18:03 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-27 13:18:03 +0000
commitafce081b90c1e2c50c3507758c7558a0dfa1f33e (patch)
tree3fb840f0bd9de41b463443ddf17131a0ad77f226 /runtime/doc/vim9.txt
parentInitial commit. (diff)
downloadvim-afce081b90c1e2c50c3507758c7558a0dfa1f33e.tar.xz
vim-afce081b90c1e2c50c3507758c7558a0dfa1f33e.zip
Adding upstream version 2:8.2.2434.upstream/2%8.2.2434upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'runtime/doc/vim9.txt')
-rw-r--r--runtime/doc/vim9.txt1487
1 files changed, 1487 insertions, 0 deletions
diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt
new file mode 100644
index 0000000..7246ff8
--- /dev/null
+++ b/runtime/doc/vim9.txt
@@ -0,0 +1,1487 @@
+*vim9.txt* For Vim version 8.2. Last change: 2021 Jan 23
+
+
+ VIM REFERENCE MANUAL by Bram Moolenaar
+
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+Vim9 script commands and expressions. *Vim9* *vim9*
+
+Most expression help is in |eval.txt|. This file is about the new syntax and
+features in Vim9 script.
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+
+1. What is Vim9 script? |Vim9-script|
+2. Differences |vim9-differences|
+3. New style functions |fast-functions|
+4. Types |vim9-types|
+5. Namespace, Import and Export |vim9script|
+6. Future work: classes |vim9-classes|
+
+9. Rationale |vim9-rationale|
+
+==============================================================================
+
+1. What is Vim9 script? *Vim9-script*
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+Vim script has been growing over time, while preserving backwards
+compatibility. That means bad choices from the past often can't be changed
+and compatibility with Vi restricts possible solutions. Execution is quite
+slow, each line is parsed every time it is executed.
+
+The main goal of Vim9 script is to drastically improve performance. This is
+accomplished by compiling commands into instructions that can be efficiently
+executed. An increase in execution speed of 10 to 100 times can be expected.
+
+A secondary goal is to avoid Vim-specific constructs and get closer to
+commonly used programming languages, such as JavaScript, TypeScript and Java.
+
+The performance improvements can only be achieved by not being 100% backwards
+compatible. For example, making function arguments available in the
+"a:" dictionary adds quite a lot of overhead. In a Vim9 function this
+dictionary is not available. Other differences are more subtle, such as how
+errors are handled.
+
+The Vim9 script syntax and semantics are used in:
+- a function defined with the `:def` command
+- a script file where the first command is `vim9script`
+- an autocommand defined in the context of the above
+
+When using `:function` in a Vim9 script file the legacy syntax is used, with
+the highest |scriptversion|. However, this can be confusing and is therefore
+discouraged.
+
+Vim9 script and legacy Vim script can be mixed. There is no requirement to
+rewrite old scripts, they keep working as before. You may want to use a few
+`:def` functions for code that needs to be fast.
+
+==============================================================================
+
+2. Differences from legacy Vim script *vim9-differences*
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+Overview ~
+
+Brief summary of the differences you will most often encounter when using Vim9
+script and `:def` functions; details are below:
+- Comments start with #, not ": >
+ echo "hello" # comment
+- Using a backslash for line continuation is hardly ever needed: >
+ echo "hello "
+ .. yourName
+ .. ", how are you?"
+- White space is required in many places.
+- Assign values without `:let`, declare variables with `:var`: >
+ var count = 0
+ count += 3
+- Constants can be declared with `:final` and `:const`: >
+ final matches = [] # add matches
+ const names = ['Betty', 'Peter'] # cannot be changed
+- `:final` cannot be used as an abbreviation of `:finally`.
+- Variables and functions are script-local by default.
+- Functions are declared with argument types and return type: >
+ def CallMe(count: number, message: string): bool
+- Call functions without `:call`: >
+ writefile(['done'], 'file.txt')
+- You cannot use `:xit`, `:t`, `:append`, `:change`, `:insert` or curly-braces
+ names.
+- A range before a command must be prefixed with a colon: >
+ :%s/this/that
+- Unless mentioned specifically, the highest |scriptversion| is used.
+
+
+Comments starting with # ~
+
+In legacy Vim script comments start with double quote. In Vim9 script
+comments start with #. >
+ # declarations
+ var count = 0 # number of occurrences
+
+The reason is that a double quote can also be the start of a string. In many
+places, especially halfway through an expression with a line break, it's hard
+to tell what the meaning is, since both a string and a comment can be followed
+by arbitrary text. To avoid confusion only # comments are recognized. This
+is the same as in shell scripts and Python programs.
+
+In Vi # is a command to list text with numbers. In Vim9 script you can use
+`:number` for that. >
+ 101 number
+
+To improve readability there must be a space between a command and the #
+that starts a comment: >
+ var name = value # comment
+ var name = value# error!
+
+In legacy Vim script # is also used for the alternate file name. In Vim9
+script you need to use %% instead. Instead of ## use %%% (stands for all
+arguments).
+
+
+Vim9 functions ~
+
+A function defined with `:def` is compiled. Execution is many times faster,
+often 10x to 100x times.
+
+Many errors are already found when compiling, before the function is executed.
+The syntax is strict, to enforce code that is easy to read and understand.
+
+Compilation is done when either of these is encountered:
+- the first time the function is called
+- when the `:defcompile` command is encountered in the script where the
+ function was defined
+- `:disassemble` is used for the function.
+- a function that is compiled calls the function or uses it as a function
+ reference
+
+`:def` has no options like `:function` does: "range", "abort", "dict" or
+"closure". A `:def` function always aborts on an error (unless `:silent!` was
+used for the command or inside a `:try` block), does not get a range passed
+cannot be a "dict" function, and can always be a closure.
+
+The argument types and return type need to be specified. The "any" type can
+be used, type checking will then be done at runtime, like with legacy
+functions.
+
+Arguments are accessed by name, without "a:", just like any other language.
+There is no "a:" dictionary or "a:000" list.
+
+Variable arguments are defined as the last argument, with a name and have a
+list type, similar to TypeScript. For example, a list of numbers: >
+ def MyFunc(...itemlist: list<number>)
+ for item in itemlist
+ ...
+
+
+Functions and variables are script-local by default ~
+ *vim9-scopes*
+When using `:function` or `:def` to specify a new function at the script level
+in a Vim9 script, the function is local to the script, as if "s:" was
+prefixed. Using the "s:" prefix is optional. To define a global function or
+variable the "g:" prefix must be used. For functions in an autoload script
+the "name#" prefix is sufficient. >
+ def ThisFunction() # script-local
+ def s:ThisFunction() # script-local
+ def g:ThatFunction() # global
+ def scriptname#function() # autoload
+
+When using `:function` or `:def` to specify a nested function inside a `:def`
+function, this nested function is local to the code block it is defined in.
+In a `:def` function it is not possible to define a script-local function. It
+is possible to define a global function by using the "g:" prefix.
+
+When referring to a function and no "s:" or "g:" prefix is used, Vim will
+search for the function:
+- in the function scope, in block scopes
+- in the script scope, possibly imported
+- in the list of global functions
+However, it is recommended to always use "g:" to refer to a global function
+for clarity.
+
+In all cases the function must be defined before used. That is when it is
+called, when `:defcompile` causes it to be compiled, or when code that calls
+it is being compiled (to figure out the return type).
+
+The result is that functions and variables without a namespace can usually be
+found in the script, either defined there or imported. Global functions and
+variables could be defined anywhere (good luck finding out where!).
+
+Global functions can still be defined and deleted at nearly any time. In
+Vim9 script script-local functions are defined once when the script is sourced
+and cannot be deleted or replaced.
+
+When compiling a function and a function call is encountered for a function
+that is not (yet) defined, the |FuncUndefined| autocommand is not triggered.
+You can use an autoload function if needed, or call a legacy function and have
+|FuncUndefined| triggered there.
+
+
+Reloading a Vim9 script clears functions and variables by default ~
+ *vim9-reload*
+When loading a legacy Vim script a second time nothing is removed, the
+commands will replace existing variables and functions and create new ones.
+
+When loading a Vim9 script a second time all existing script-local functions
+and variables are deleted, thus you start with a clean slate. This is useful
+if you are developing a plugin and want to try a new version. If you renamed
+something you don't have to worry about the old name still hanging around.
+
+If you do want to keep items, use: >
+ vim9script noclear
+
+You want to use this in scripts that use a `finish` command to bail out at
+some point when loaded again. E.g. when a buffer local option is set: >
+ vim9script noclear
+ setlocal completefunc=SomeFunc
+ if exists('*g:SomeFunc') | finish | endif
+ def g:SomeFunc()
+ ....
+
+
+Variable declarations with :var, :final and :const ~
+ *vim9-declaration* *:var*
+Local variables need to be declared with `:var`. Local constants need to be
+declared with `:final` or `:const`. We refer to both as "variables" in this
+section.
+
+Variables can be local to a script, function or code block: >
+ vim9script
+ var script_var = 123
+ def SomeFunc()
+ var func_var = script_var
+ if cond
+ var block_var = func_var
+ ...
+
+The variables are only visible in the block where they are defined and nested
+blocks. Once the block ends the variable is no longer accessible: >
+ if cond
+ var inner = 5
+ else
+ var inner = 0
+ endif
+ echo inner # Error!
+
+The declaration must be done earlier: >
+ var inner: number
+ if cond
+ inner = 5
+ else
+ inner = 0
+ endif
+ echo inner
+
+To intentionally hide a variable from code that follows, a block can be
+used: >
+ {
+ var temp = 'temp'
+ ...
+ }
+ echo temp # Error!
+
+Declaring a variable with a type but without an initializer will initialize to
+zero, false or empty.
+
+In Vim9 script `:let` cannot be used. An existing variable is assigned to
+without any command. The same for global, window, tab, buffer and Vim
+variables, because they are not really declared. They can also be deleted
+with `:unlet`.
+
+Variables and functions cannot shadow previously defined or imported variables
+and functions.
+Variables may shadow Ex commands, rename the variable if needed.
+
+Global variables and user defined functions must be prefixed with "g:", also
+at the script level. >
+ vim9script
+ var script_local = 'text'
+ g:global = 'value'
+ var Funcref = g:ThatFunction
+
+Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be
+used to repeat a `:substitute` command.
+
+
+Constants ~
+ *vim9-const* *vim9-final*
+How constants work varies between languages. Some consider a variable that
+can't be assigned another value a constant. JavaScript is an example. Others
+also make the value immutable, thus when a constant uses a list, the list
+cannot be changed. In Vim9 we can use both.
+
+`:const` is used for making both the variable and the value a constant. Use
+this for composite structures that you want to make sure will not be modified.
+Example: >
+ const myList = [1, 2]
+ myList = [3, 4] # Error!
+ myList[0] = 9 # Error!
+ muList->add(3) # Error!
+< *:final*
+`:final` is used for making only the variable a constant, the value can be
+changed. This is well known from Java. Example: >
+ final myList = [1, 2]
+ myList = [3, 4] # Error!
+ myList[0] = 9 # OK
+ muList->add(3) # OK
+
+It is common to write constants as ALL_CAPS, but you don't have to.
+
+The constant only applies to the value itself, not what it refers to. >
+ final females = ["Mary"]
+ const NAMES = [["John", "Peter"], females]
+ NAMES[0] = ["Jack"] # Error!
+ NAMES[0][0] = "Jack" # Error!
+ NAMES[1] = ["Emma"] # Error!
+ NAMES[1][0] = "Emma" # OK, now females[0] == "Emma"
+
+< *E1092*
+Declaring more than one variable at a time, using the unpack notation, is
+currently not supported: >
+ var [v1, v2] = GetValues() # Error!
+That is because the type needs to be inferred from the list item type, which
+isn't that easy.
+
+
+Omitting :call and :eval ~
+
+Functions can be called without `:call`: >
+ writefile(lines, 'file')
+Using `:call` is still possible, but this is discouraged.
+
+A method call without `eval` is possible, so long as the start is an
+identifier or can't be an Ex command. Examples: >
+ myList->add(123)
+ g:myList->add(123)
+ [1, 2, 3]->Process()
+ {a: 1, b: 2}->Process()
+ "foobar"->Process()
+ ("foobar")->Process()
+ 'foobar'->Process()
+ ('foobar')->Process()
+
+In the rare case there is ambiguity between a function name and an Ex command,
+prepend ":" to make clear you want to use the Ex command. For example, there
+is both the `:substitute` command and the `substitute()` function. When the
+line starts with `substitute(` this will use the function. Prepend a colon to
+use the command instead: >
+ :substitute(pattern (replacement (
+
+Note that while variables need to be defined before they can be used,
+functions can be called before being defined. This is required to allow
+for cyclic dependencies between functions. It is slightly less efficient,
+since the function has to be looked up by name. And a typo in the function
+name will only be found when the function is called.
+
+
+Omitting function() ~
+
+A user defined function can be used as a function reference in an expression
+without `function()`. The argument types and return type will then be checked.
+The function must already have been defined. >
+
+ var Funcref = MyFunction
+
+When using `function()` the resulting type is "func", a function with any
+number of arguments and any return type. The function can be defined later.
+
+
+Lambda using => instead of -> ~
+
+In legacy script there can be confusion between using "->" for a method call
+and for a lambda. Also, when a "{" is found the parser needs to figure out if
+it is the start of a lambda or a dictionary, which is now more complicated
+because of the use of argument types.
+
+To avoid these problems Vim9 script uses a different syntax for a lambda,
+which is similar to Javascript: >
+ var Lambda = (arg) => expression
+
+No line break is allowed in the arguments of a lambda up to and including the
+"=>". This is OK: >
+ filter(list, (k, v) =>
+ v > 0)
+This does not work: >
+ filter(list, (k, v)
+ => v > 0)
+This also does not work: >
+ filter(list, (k,
+ v) => v > 0)
+But you can use a backslash to concatenate the lines before parsing: >
+ filter(list, (k,
+ \ v)
+ \ => v > 0)
+
+Additionally, a lambda can contain statements in {}: >
+ var Lambda = (arg) => {
+ g:was_called = 'yes'
+ return expression
+ }
+NOT IMPLEMENTED YET
+
+ *vim9-curly*
+To avoid the "{" of a dictionary literal to be recognized as a statement block
+wrap it in parenthesis: >
+ var Lambda = (arg) => ({key: 42})
+
+Also when confused with the start of a command block: >
+ ({
+ key: value
+ })->method()
+
+
+Automatic line continuation ~
+
+In many cases it is obvious that an expression continues on the next line. In
+those cases there is no need to prefix the line with a backslash (see
+|line-continuation|). For example, when a list spans multiple lines: >
+ var mylist = [
+ 'one',
+ 'two',
+ ]
+And when a dict spans multiple lines: >
+ var mydict = {
+ one: 1,
+ two: 2,
+ }
+Function call: >
+ var result = Func(
+ arg1,
+ arg2
+ )
+
+For binary operators in expressions not in [], {} or () a line break is
+possible just before or after the operator. For example: >
+ var text = lead
+ .. middle
+ .. end
+ var total = start +
+ end -
+ correction
+ var result = positive
+ ? PosFunc(arg)
+ : NegFunc(arg)
+
+For a method call using "->" and a member using a dot, a line break is allowed
+before it: >
+ var result = GetBuilder()
+ ->BuilderSetWidth(333)
+ ->BuilderSetHeight(777)
+ ->BuilderBuild()
+ var result = MyDict
+ .member
+
+For commands that have an argument that is a list of commands, the | character
+at the start of the line indicates line continuation: >
+ autocmd BufNewFile *.match if condition
+ | echo 'match'
+ | endif
+
+< *E1050*
+To make it possible for the operator at the start of the line to be
+recognized, it is required to put a colon before a range. This will add
+"start" and print: >
+ var result = start
+ + print
+Like this: >
+ var result = start + print
+
+This will assign "start" and print a line: >
+ var result = start
+ :+ print
+
+Note that the colon is not required for the |+cmd| argument: >
+ edit +6 fname
+
+It is also possible to split a function header over multiple lines, in between
+arguments: >
+ def MyFunc(
+ text: string,
+ separator = '-'
+ ): string
+
+Since a continuation line cannot be easily recognized the parsing of commands
+has been made stricter. E.g., because of the error in the first line, the
+second line is seen as a separate command: >
+ popup_create(some invalid expression, {
+ exit_cb: Func})
+Now "exit_cb: Func})" is actually a valid command: save any changes to the
+file "_cb: Func})" and exit. To avoid this kind of mistake in Vim9 script
+there must be white space between most command names and the argument.
+
+However, the argument of a command that is a command won't be recognized. For
+example, after "windo echo expr" a line break inside "expr" will not be seen.
+
+
+Notes:
+- "enddef" cannot be used at the start of a continuation line, it ends the
+ current function.
+- No line break is allowed in the LHS of an assignment. Specifically when
+ unpacking a list |:let-unpack|. This is OK: >
+ [var1, var2] =
+ Func()
+< This does not work: >
+ [var1,
+ var2] =
+ Func()
+- No line break is allowed in between arguments of an `:echo`, `:execute` and
+ similar commands. This is OK: >
+ echo [1,
+ 2] [3,
+ 4]
+< This does not work: >
+ echo [1, 2]
+ [3, 4]
+
+No curly braces expansion ~
+
+|curly-braces-names| cannot be used.
+
+
+Dictionary literals ~
+
+Traditionally Vim has supported dictionary literals with a {} syntax: >
+ let dict = {'key': value}
+
+Later it became clear that using a simple text key is very common, thus
+literal dictionaries were introduced in a backwards compatible way: >
+ let dict = #{key: value}
+
+However, this #{} syntax is unlike any existing language. As it turns out
+that using a literal key is much more common than using an expression, and
+considering that JavaScript uses this syntax, using the {} form for dictionary
+literals is considered a much more useful syntax. In Vim9 script the {} form
+uses literal keys: >
+ var dict = {key: value}
+
+This works for alphanumeric characters, underscore and dash. If you want to
+use another character, use a single or double quoted string: >
+ var dict = {'key with space': value}
+ var dict = {"key\twith\ttabs": value}
+ var dict = {'': value} # empty key
+
+In case the key needs to be an expression, square brackets can be used, just
+like in JavaScript: >
+ var dict = {["key" .. nr]: value}
+
+
+No :xit, :t, :append, :change or :insert ~
+
+These commands are too easily confused with local variable names.
+Instead of `:x` or `:xit` you can use `:exit`.
+Instead of `:t` you can use `:copy`.
+
+
+Comparators ~
+
+The 'ignorecase' option is not used for comparators that use strings.
+
+
+For loop ~
+
+Legacy Vim script has some tricks to make a for loop over a list handle
+deleting items at the current or previous item. In Vim9 script it just uses
+the index, if items are deleted then items in the list will be skipped.
+Example legacy script: >
+ let l = [1, 2, 3, 4]
+ for i in l
+ echo i
+ call remove(l, index(l, i))
+ endfor
+Would echo:
+ 1
+ 2
+ 3
+ 4
+In compiled Vim9 script you get:
+ 1
+ 3
+Generally, you should not change the list that is iterated over. Make a copy
+first if needed.
+
+
+White space ~
+
+Vim9 script enforces proper use of white space. This is no longer allowed: >
+ var name=234 # Error!
+ var name= 234 # Error!
+ var name =234 # Error!
+There must be white space before and after the "=": >
+ var name = 234 # OK
+White space must also be put before the # that starts a comment after a
+command: >
+ var name = 234# Error!
+ var name = 234 # OK
+
+White space is required around most operators.
+
+White space is required in a sublist (list slice) around the ":", except at
+the start and end: >
+ otherlist = mylist[v : count] # v:count has a different meaning
+ otherlist = mylist[:] # make a copy of the List
+ otherlist = mylist[v :]
+ otherlist = mylist[: v]
+
+White space is not allowed:
+- Between a function name and the "(": >
+ Func (arg) # Error!
+ Func
+ \ (arg) # Error!
+ Func
+ (arg) # Error!
+ Func(arg) # OK
+ Func(
+ arg) # OK
+ Func(
+ arg # OK
+ )
+
+
+Conditions and expressions ~
+
+Conditions and expressions are mostly working like they do in other languages.
+Some values are different from legacy Vim script:
+ value legacy Vim script Vim9 script ~
+ 0 falsy falsy
+ 1 truthy truthy
+ 99 truthy Error!
+ "0" falsy Error!
+ "99" truthy Error!
+ "text" falsy Error!
+
+For the "??" operator and when using "!" then there is no error, every value
+is either falsy or truthy. This is mostly like JavaScript, except that an
+empty list and dict is falsy:
+
+ type truthy when ~
+ bool true, v:true or 1
+ number non-zero
+ float non-zero
+ string non-empty
+ blob non-empty
+ list non-empty (different from JavaScript)
+ dictionary non-empty (different from JavaScript)
+ func when there is a function name
+ special true or v:true
+ job when not NULL
+ channel when not NULL
+ class when not NULL
+ object when not NULL (TODO: when isTrue() returns true)
+
+The boolean operators "||" and "&&" expect the values to be boolean, zero or
+one: >
+ 1 || false == true
+ 0 || 1 == true
+ 0 || false == false
+ 1 && true == true
+ 0 && 1 == false
+ 8 || 0 Error!
+ 'yes' && 0 Error!
+ [] || 99 Error!
+
+When using "!" for inverting, there is no error for using any type and the
+result is a boolean. "!!" can be used to turn any value into boolean: >
+ !'yes' == false
+ !![] == false
+ !![1, 2, 3] == true
+
+When using "`.."` for string concatenation arguments of simple types are
+always converted to string: >
+ 'hello ' .. 123 == 'hello 123'
+ 'hello ' .. v:true == 'hello true'
+
+Simple types are string, float, special and bool. For other types |string()|
+can be used.
+ *false* *true* *null*
+In Vim9 script one can use "true" for v:true, "false" for v:false and "null"
+for v:null. When converting a boolean to a string "false" and "true" are
+used, not "v:false" and "v:true" like in legacy script. "v:none" is not
+changed, it is only used in JSON and has no equivalent in other languages.
+
+Indexing a string with [idx] or [idx : idx] uses character indexes instead of
+byte indexes. Example: >
+ echo 'bár'[1]
+In legacy script this results in the character 0xc3 (an illegal byte), in Vim9
+script this results in the string 'á'.
+A negative index is counting from the end, "[-1]" is the last character.
+To exclude the last character use |slice()|.
+If the index is out of range then an empty string results.
+
+In legacy script "++var" and "--var" would be silently accepted and have no
+effect. This is an error in Vim9 script.
+
+Numbers starting with zero are not considered to be octal, only numbers
+starting with "0o" are octal: "0o744". |scriptversion-4|
+
+
+What to watch out for ~
+ *vim9-gotchas*
+Vim9 was designed to be closer to often used programming languages, but at the
+same time tries to support the legacy Vim commands. Some compromises had to
+be made. Here is a summary of what might be unexpected.
+
+Ex command ranges need to be prefixed with a colon. >
+ -> legacy Vim: shifts the previous line to the right
+ ->func() Vim9: method call in a continuation line
+ :-> Vim9: shifts the previous line to the right
+
+ %s/a/b legacy Vim: substitute on all lines
+ x = alongname
+ % another Vim9: modulo operator in a continuation line
+ :%s/a/b Vim9: substitute on all lines
+ 't legacy Vim: jump to mark t
+ 'text'->func() Vim9: method call
+ :'t Vim9: jump to mark t
+
+Some Ex commands can be confused with assignments in Vim9 script: >
+ g:name = value # assignment
+ g:pattern:cmd # invalid command - ERROR
+ :g:pattern:cmd # :global command
+
+Functions defined with `:def` compile the whole function. Legacy functions
+can bail out, and the following lines are not parsed: >
+ func Maybe()
+ if !has('feature')
+ return
+ endif
+ use-feature
+ endfunc
+Vim9 functions are compiled as a whole: >
+ def Maybe()
+ if !has('feature')
+ return
+ endif
+ use-feature # May give a compilation error
+ enddef
+For a workaround, split it in two functions: >
+ func Maybe()
+ if has('feature')
+ call MaybeInner()
+ endif
+ endfunc
+ if has('feature')
+ def MaybeInner()
+ use-feature
+ enddef
+ endif
+Or put the unsupported code inside an `if` with a constant expression that
+evaluates to false: >
+ def Maybe()
+ if has('feature')
+ use-feature
+ endif
+ enddef
+< *vim9-user-command*
+Another side effect of compiling a function is that the presence of a user
+command is checked at compile time. If the user command is defined later an
+error will result. This works: >
+ command -nargs=1 MyCommand echom <q-args>
+ def Works()
+ MyCommand 123
+ enddef
+This will give an error for "MyCommand" not being defined: >
+ def Works()
+ command -nargs=1 MyCommand echom <q-args>
+ MyCommand 123
+ enddef
+A workaround is to invoke the command indirectly with `:execute`: >
+ def Works()
+ command -nargs=1 MyCommand echom <q-args>
+ execute 'MyCommand 123'
+ enddef
+
+Note that for unrecognized commands there is no check for "|" and a following
+command. This will give an error for missing `endif`: >
+ def Maybe()
+ if has('feature') | use-feature | endif
+ enddef
+
+Other differences ~
+
+Patterns are used like 'magic' is set, unless explicitly overruled.
+The 'edcompatible' option value is not used.
+The 'gdefault' option value is not used.
+
+
+==============================================================================
+
+3. New style functions *fast-functions*
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+ *:def*
+:def[!] {name}([arguments])[: {return-type}]
+ Define a new function by the name {name}. The body of
+ the function follows in the next lines, until the
+ matching `:enddef`.
+
+ When {return-type} is omitted or is "void" the
+ function is not expected to return anything.
+
+ {arguments} is a sequence of zero or more argument
+ declarations. There are three forms:
+ {name}: {type}
+ {name} = {value}
+ {name}: {type} = {value}
+ The first form is a mandatory argument, the caller
+ must always provide them.
+ The second and third form are optional arguments.
+ When the caller omits an argument the {value} is used.
+
+ The function will be compiled into instructions when
+ called, or when `:disassemble` or `:defcompile` is
+ used. Syntax and type errors will be produced at that
+ time.
+
+ It is possible to nest `:def` inside another `:def` or
+ `:function` up to about 50 levels deep.
+
+ [!] is used as with `:function`. Note that
+ script-local functions cannot be deleted or redefined
+ later in Vim9 script. They can only be removed by
+ reloading the same script.
+
+ *:enddef*
+:enddef End of a function defined with `:def`. It should be on
+ a line by its own.
+
+
+If the script the function is defined in is Vim9 script, then script-local
+variables can be accessed without the "s:" prefix. They must be defined
+before the function is compiled. If the script the function is defined in is
+legacy script, then script-local variables must be accessed with the "s:"
+prefix and they do not need to exist (they can be deleted any time).
+
+ *:defc* *:defcompile*
+:defc[ompile] Compile functions defined in the current script that
+ were not compiled yet.
+ This will report errors found during the compilation.
+
+ *:disa* *:disassemble*
+:disa[ssemble] {func} Show the instructions generated for {func}.
+ This is for debugging and testing.
+ Note that for command line completion of {func} you
+ can prepend "s:" to find script-local functions.
+
+:disa[ssemble]! {func} Like `:disassemble` but with the instructions used for
+ profiling.
+
+Limitations ~
+
+Local variables will not be visible to string evaluation. For example: >
+ def MapList(): list<string>
+ var list = ['aa', 'bb', 'cc', 'dd']
+ return range(1, 2)->map('list[v:val]')
+ enddef
+
+The map argument is a string expression, which is evaluated without the
+function scope. Instead, use a lambda: >
+ def MapList(): list<string>
+ var list = ['aa', 'bb', 'cc', 'dd']
+ return range(1, 2)->map(( _, v) => list[v])
+ enddef
+
+The same is true for commands that are not compiled, such as `:global`.
+For these the backtick expansion can be used. Example: >
+ def Replace()
+ var newText = 'blah'
+ g/pattern/s/^/`=newText`/
+ enddef
+
+==============================================================================
+
+4. Types *vim9-types*
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+The following builtin types are supported:
+ bool
+ number
+ float
+ string
+ blob
+ list<{type}>
+ dict<{type}>
+ job
+ channel
+ func
+ func: {type}
+ func({type}, ...)
+ func({type}, ...): {type}
+
+Not supported yet:
+ tuple<a: {type}, b: {type}, ...>
+
+These types can be used in declarations, but no value will have this type:
+ {type}|{type} {not implemented yet}
+ void
+ any
+
+There is no array type, use list<{type}> instead. For a list constant an
+efficient implementation is used that avoids allocating lot of small pieces of
+memory.
+
+A partial and function can be declared in more or less specific ways:
+func any kind of function reference, no type
+ checking for arguments or return value
+func: {type} any number and type of arguments with specific
+ return type
+func({type}) function with argument type, does not return
+ a value
+func({type}): {type} function with argument type and return type
+func(?{type}) function with type of optional argument, does
+ not return a value
+func(...{type}) function with type of variable number of
+ arguments, does not return a value
+func({type}, ?{type}, ...{type}): {type}
+ function with:
+ - type of mandatory argument
+ - type of optional argument
+ - type of variable number of arguments
+ - return type
+
+If the return type is "void" the function does not return a value.
+
+The reference can also be a |Partial|, in which case it stores extra arguments
+and/or a dictionary, which are not visible to the caller. Since they are
+called in the same way the declaration is the same.
+
+Custom types can be defined with `:type`: >
+ :type MyList list<string>
+Custom types must start with a capital letter, to avoid name clashes with
+builtin types added later, similarly to user functions.
+{not implemented yet}
+
+And classes and interfaces can be used as types: >
+ :class MyClass
+ :var mine: MyClass
+
+ :interface MyInterface
+ :var mine: MyInterface
+
+ :class MyTemplate<Targ>
+ :var mine: MyTemplate<number>
+ :var mine: MyTemplate<string>
+
+ :class MyInterface<Targ>
+ :var mine: MyInterface<number>
+ :var mine: MyInterface<string>
+{not implemented yet}
+
+
+Variable types and type casting ~
+ *variable-types*
+Variables declared in Vim9 script or in a `:def` function have a type, either
+specified explicitly or inferred from the initialization.
+
+Global, buffer, window and tab page variables do not have a specific type, the
+value can be changed at any time, possibly changing the type. Therefore, in
+compiled code the "any" type is assumed.
+
+This can be a problem when the "any" type is undesired and the actual type is
+expected to always be the same. For example, when declaring a list: >
+ var l: list<number> = [1, g:two]
+At compile time Vim doesn't know the type of "g:two" and the expression type
+becomes list<any>. An instruction is generated to check the list type before
+doing the assignment, which is a bit inefficient.
+ *type-casting*
+To avoid this, use a type cast: >
+ var l: list<number> = [1, <number>g:two]
+The compiled code will then only check that "g:two" is a number and give an
+error if it isn't. This is called type casting.
+
+The syntax of a type cast is: "<" {type} ">". There cannot be white space
+after the "<" or before the ">" (to avoid them being confused with
+smaller-than and bigger-than operators).
+
+The semantics is that, if needed, a runtime type check is performed. The
+value is not actually changed. If you need to change the type, e.g. to change
+it to a string, use the |string()| function. Or use |str2nr()| to convert a
+string to a number.
+
+
+Type inference ~
+ *type-inference*
+In general: Whenever the type is clear it can be omitted. For example, when
+declaring a variable and giving it a value: >
+ var name = 0 # infers number type
+ var name = 'hello' # infers string type
+
+The type of a list and dictionary comes from the common type of the values.
+If the values all have the same type, that type is used for the list or
+dictionary. If there is a mix of types, the "any" type is used. >
+ [1, 2, 3] list<number>
+ ['a', 'b', 'c'] list<string>
+ [1, 'x', 3] list<any>
+
+
+Stricter type checking ~
+ *type-checking*
+In legacy Vim script, where a number was expected, a string would be
+automatically converted to a number. This was convenient for an actual number
+such as "123", but leads to unexpected problems (but no error message) if the
+string doesn't start with a number. Quite often this leads to hard-to-find
+bugs.
+
+In Vim9 script this has been made stricter. In most places it works just as
+before, if the value used matches the expected type. There will sometimes be
+an error, thus breaking backwards compatibility. For example:
+- Using a number other than 0 or 1 where a boolean is expected. *E1023*
+- Using a string value when setting a number options.
+- Using a number where a string is expected. *E1024*
+
+One consequence is that the item type of a list or dict given to map() must
+not change. This will give an error in compiled code: >
+ map([1, 2, 3], (i, v) => 'item ' .. i)
+ E1012: Type mismatch; expected list<number> but got list<string>
+Instead use |mapnew()|.
+
+==============================================================================
+
+5. Namespace, Import and Export
+ *vim9script* *vim9-export* *vim9-import*
+
+THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
+
+A Vim9 script can be written to be imported. This means that everything in
+the script is local, unless exported. Those exported items, and only those
+items, can then be imported in another script.
+
+You can cheat by using the global namespace explicitly. We will assume here
+that you don't do that.
+
+
+Namespace ~
+ *vim9-namespace*
+To recognize a file that can be imported the `vim9script` statement must
+appear as the first statement in the file. It tells Vim to interpret the
+script in its own namespace, instead of the global namespace. If a file
+starts with: >
+ vim9script
+ var myvar = 'yes'
+Then "myvar" will only exist in this file. While without `vim9script` it would
+be available as `g:myvar` from any other script and function.
+
+The variables at the file level are very much like the script-local "s:"
+variables in legacy Vim script, but the "s:" is omitted. And they cannot be
+deleted.
+
+In Vim9 script the global "g:" namespace can still be used as before. And the
+"w:", "b:" and "t:" namespaces. These have in common that variables are not
+declared and they can be deleted.
+
+A side effect of `:vim9script` is that the 'cpoptions' option is set to the
+Vim default value, like with: >
+ :set cpo&vim
+One of the effects is that |line-continuation| is always enabled.
+The original value of 'cpoptions' is restored at the end of the script.
+
+
+Export ~
+ *:export* *:exp*
+Exporting an item can be written as: >
+ export const EXPORTED_CONST = 1234
+ export var someValue = ...
+ export final someValue = ...
+ export const someValue = ...
+ export def MyFunc() ...
+ export class MyClass ...
+
+As this suggests, only constants, variables, `:def` functions and classes can
+be exported. {classes are not implemented yet}
+
+ *E1042*
+`:export` can only be used in Vim9 script, at the script level.
+
+
+Import ~
+ *:import* *:imp* *E1094*
+The exported items can be imported individually in another Vim9 script: >
+ import EXPORTED_CONST from "thatscript.vim"
+ import MyClass from "myclass.vim"
+
+To import multiple items at the same time: >
+ import {someValue, MyClass} from "thatscript.vim"
+
+In case the name is ambiguous, another name can be specified: >
+ import MyClass as ThatClass from "myclass.vim"
+ import {someValue, MyClass as ThatClass} from "myclass.vim"
+
+To import all exported items under a specific identifier: >
+ import * as That from 'thatscript.vim'
+
+{not implemented yet: using "This as That"}
+
+Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free
+to choose the name "That", but it is highly recommended to use the name of the
+script file to avoid confusion.
+
+`:import` can also be used in legacy Vim script. The imported items still
+become script-local, even when the "s:" prefix is not given.
+
+The script name after `import` can be:
+- A relative path, starting "." or "..". This finds a file relative to the
+ location of the script file itself. This is useful to split up a large
+ plugin into several files.
+- An absolute path, starting with "/" on Unix or "D:/" on MS-Windows. This
+ will rarely be used.
+- A path not being relative or absolute. This will be found in the
+ "import" subdirectories of 'runtimepath' entries. The name will usually be
+ longer and unique, to avoid loading the wrong file.
+
+Once a vim9 script file has been imported, the result is cached and used the
+next time the same script is imported. It will not be read again.
+ *:import-cycle*
+The `import` commands are executed when encountered. If that script (directly
+or indirectly) imports the current script, then items defined after the
+`import` won't be processed yet. Therefore cyclic imports can exist, but may
+result in undefined items.
+
+
+Import in an autoload script ~
+
+For optimal startup speed, loading scripts should be postponed until they are
+actually needed. A recommended mechanism:
+
+1. In the plugin define user commands, functions and/or mappings that refer to
+ an autoload script. >
+ command -nargs=1 SearchForStuff searchfor#Stuff(<f-args>)
+
+< This goes in .../plugin/anyname.vim. "anyname.vim" can be freely chosen.
+
+2. In the autoload script do the actual work. You can import items from
+ other files to split up functionality in appropriate pieces. >
+ vim9script
+ import FilterFunc from "../import/someother.vim"
+ def searchfor#Stuff(arg: string)
+ var filtered = FilterFunc(arg)
+ ...
+< This goes in .../autoload/searchfor.vim. "searchfor" in the file name
+ must be exactly the same as the prefix for the function name, that is how
+ Vim finds the file.
+
+3. Other functionality, possibly shared between plugins, contains the exported
+ items and any private items. >
+ vim9script
+ var localVar = 'local'
+ export def FilterFunc(arg: string): string
+ ...
+< This goes in .../import/someother.vim.
+
+When compiling a `:def` function and a function in an autoload script is
+encountered, the script is not loaded until the `:def` function is called.
+
+
+Import in legacy Vim script ~
+
+If an `import` statement is used in legacy Vim script, the script-local "s:"
+namespace will be used for the imported item, even when "s:" is not specified.
+
+
+==============================================================================
+
+6. Future work: classes *vim9-classes*
+
+Above "class" was mentioned a few times, but it has not been implemented yet.
+Most of Vim9 script can be created without this functionality, and since
+implementing classes is going to be a lot of work, it is left for the future.
+For now we'll just make sure classes can be added later.
+
+Thoughts:
+- `class` / `endclass`, everything in one file
+- Class names are always CamelCase
+- Single constructor
+- Single inheritance with `class ThisClass extends BaseClass`
+- `abstract class`
+- `interface` (Abstract class without any implementation)
+- `class SomeClass implements SomeInterface`
+- Generics for class: `class <Tkey, Tentry>`
+- Generics for function: `def <Tkey> GetLast(key: Tkey)`
+
+Again, much of this is from TypeScript.
+
+Some things that look like good additions:
+- Use a class as an interface (like Dart)
+- Extend a class with methods, using an import (like Dart)
+
+An important class that will be provided is "Promise". Since Vim is single
+threaded, connecting asynchronous operations is a natural way of allowing
+plugins to do their work without blocking the user. It's a uniform way to
+invoke callbacks and handle timeouts and errors.
+
+==============================================================================
+
+9. Rationale *vim9-rationale*
+
+The :def command ~
+
+Plugin writers have asked for much faster Vim script. Investigations have
+shown that keeping the existing semantics of function calls make this close to
+impossible, because of the overhead involved with calling a function, setting
+up the local function scope and executing lines. There are many details that
+need to be handled, such as error messages and exceptions. The need to create
+a dictionary for a: and l: scopes, the a:000 list and several others add too
+much overhead that cannot be avoided.
+
+Therefore the `:def` method to define a new-style function had to be added,
+which allows for a function with different semantics. Most things still work
+as before, but some parts do not. A new way to define a function was
+considered the best way to separate the legacy style code from Vim9 style code.
+
+Using "def" to define a function comes from Python. Other languages use
+"function" which clashes with legacy Vim script.
+
+
+Type checking ~
+
+When compiling lines of Vim commands into instructions as much as possible
+should be done at compile time. Postponing it to runtime makes the execution
+slower and means mistakes are found only later. For example, when
+encountering the "+" character and compiling this into a generic add
+instruction, at runtime the instruction would have to inspect the type of the
+arguments and decide what kind of addition to do. And when the type is
+dictionary throw an error. If the types are known to be numbers then an "add
+number" instruction can be used, which is faster. The error can be given at
+compile time, no error handling is needed at runtime, since adding two numbers
+cannot fail.
+
+The syntax for types, using <type> for compound types, is similar to Java. It
+is easy to understand and widely used. The type names are what were used in
+Vim before, with some additions such as "void" and "bool".
+
+
+Removing clutter and weirdness ~
+
+Once decided that `:def` functions have different syntax than legacy functions,
+we are free to add improvements to make the code more familiar for users who
+know popular programming languages. In other words: remove weird things that
+only Vim does.
+
+We can also remove clutter, mainly things that were done to make Vim script
+backwards compatible with the good old Vi commands.
+
+Examples:
+- Drop `:call` for calling a function and `:eval` for manipulating data.
+- Drop using a leading backslash for line continuation, automatically figure
+ out where an expression ends.
+
+However, this does require that some things need to change:
+- Comments start with # instead of ", to avoid confusing them with strings.
+ This is good anyway, it is known from several popular languages.
+- Ex command ranges need to be prefixed with a colon, to avoid confusion with
+ expressions (single quote can be a string or a mark, "/" can be divide or a
+ search command, etc.).
+
+Goal is to limit the differences. A good criteria is that when the old syntax
+is accidentally used you are very likely to get an error message.
+
+
+Syntax and semantics from popular languages ~
+
+Script writers have complained that the Vim script syntax is unexpectedly
+different from what they are used to. To reduce this complaint popular
+languages are used as an example. At the same time, we do not want to abandon
+the well-known parts of legacy Vim script.
+
+For many things TypeScript is followed. It's a recent language that is
+gaining popularity and has similarities with Vim script. It also has a
+mix of static typing (a variable always has a known value type) and dynamic
+typing (a variable can have different types, this changes at runtime). Since
+legacy Vim script is dynamically typed and a lot of existing functionality
+(esp. builtin functions) depends on that, while static typing allows for much
+faster execution, we need to have this mix in Vim9 script.
+
+There is no intention to completely match TypeScript syntax and semantics. We
+just want to take those parts that we can use for Vim and we expect Vim users
+will be happy with. TypeScript is a complex language with its own history,
+advantages and disadvantages. To get an idea of the disadvantages read the
+book: "JavaScript: The Good Parts". Or find the article "TypeScript: the good
+parts" and read the "Things to avoid" section.
+
+People familiar with other languages (Java, Python, etc.) will also find
+things in TypeScript that they do not like or do not understand. We'll try to
+avoid those things.
+
+Specific items from TypeScript we avoid:
+- Overloading "+", using it both for addition and string concatenation. This
+ goes against legacy Vim script and often leads to mistakes. For that reason
+ we will keep using ".." for string concatenation. Lua also uses ".." this
+ way. And it allows for conversion to string for more values.
+- TypeScript can use an expression like "99 || 'yes'" in a condition, but
+ cannot assign the value to a boolean. That is inconsistent and can be
+ annoying. Vim recognizes an expression with && or || and allows using the
+ result as a bool. TODO: to be reconsidered
+- TypeScript considers an empty string as Falsy, but an empty list or dict as
+ Truthy. That is inconsistent. In Vim an empty list and dict are also
+ Falsy.
+- TypeScript has various "Readonly" types, which have limited usefulness,
+ since a type cast can remove the immutable nature. Vim locks the value,
+ which is more flexible, but is only checked at runtime.
+
+
+Declarations ~
+
+Legacy Vim script uses `:let` for every assignment, while in Vim9 declarations
+are used. That is different, thus it's good to use a different command:
+`:var`. This is used in many languages. The semantics might be slightly
+different, but it's easily recognized as a declaration.
+
+Using `:const` for constants is common, but the semantics varies. Some
+languages only make the variable immutable, others also make the value
+immutable. Since "final" is well known from Java for only making the variable
+immutable we decided to use that. And then `:const` can be used for making
+both immutable. This was also used in legacy Vim script and the meaning is
+almost the same.
+
+What we end up with is very similar to Dart: >
+ :var name # mutable variable and value
+ :final name # immutable variable, mutable value
+ :const name # immutable variable and value
+
+Since legacy and Vim9 script will be mixed and global variables will be
+shared, optional type checking is desirable. Also, type inference will avoid
+the need for specifying the type in many cases. The TypeScript syntax fits
+best for adding types to declarations: >
+ var name: string # string type is specified
+ ...
+ name = 'John'
+ const greeting = 'hello' # string type is inferred
+
+This is how we put types in a declaration: >
+ var mylist: list<string>
+ final mylist: list<string> = ['foo']
+ def Func(arg1: number, arg2: string): bool
+
+Two alternatives were considered:
+1. Put the type before the name, like Dart: >
+ var list<string> mylist
+ final list<string> mylist = ['foo']
+ def Func(number arg1, string arg2) bool
+2. Put the type after the variable name, but do not use a colon, like Go: >
+ var mylist list<string>
+ final mylist list<string> = ['foo']
+ def Func(arg1 number, arg2 string) bool
+
+The first is more familiar for anyone used to C or Java. The second one
+doesn't really have an advantage over the first, so let's discard the second.
+
+Since we use type inference the type can be left out when it can be inferred
+from the value. This means that after `var` we don't know if a type or a name
+follows. That makes parsing harder, not only for Vim but also for humans.
+Also, it will not be allowed to use a variable name that could be a type name,
+using `var string string` is too confusing.
+
+The chosen syntax, using a colon to separate the name from the type, adds
+punctuation, but it actually makes it easier to recognize the parts of a
+declaration.
+
+
+Expressions ~
+
+Expression evaluation was already close to what other languages are doing.
+Some details are unexpected and can be improved. For example a boolean
+condition would accept a string, convert it to a number and check if the
+number is non-zero. This is unexpected and often leads to mistakes, since
+text not starting with a number would be converted to zero, which is
+considered false. Thus using a string for a condition would often not give an
+error and be considered false. That is confusing.
+
+In Vim9 type checking is stricter to avoid mistakes. Where a condition is
+used, e.g. with the `:if` command and the `||` operator, only boolean-like
+values are accepted:
+ true: `true`, `v:true`, `1`, `0 < 9`
+ false: `false`, `v:false`, `0`, `0 > 9`
+Note that the number zero is false and the number one is true. This is more
+permissive than most other languages. It was done because many builtin
+functions return these values.
+
+If you have any type of value and want to use it as a boolean, use the `!!`
+operator:
+ true: !`!'text'`, `!![99]`, `!!{'x': 1}`, `!!99`
+ false: `!!''`, `!![]`, `!!{}`
+
+From a language like JavaScript we have this handy construct: >
+ GetName() || 'unknown'
+However, this conflicts with only allowing a boolean for a condition.
+Therefore the "??" operator was added: >
+ GetName() ?? 'unknown'
+Here you can explicitly express your intention to use the value as-is and not
+result in a boolean. This is called the |falsy-operator|.
+
+
+Import and Export ~
+
+A problem of legacy Vim script is that by default all functions and variables
+are global. It is possible to make them script-local, but then they are not
+available in other scripts. This defies the concept of a package that only
+exports selected items and keeps the rest local.
+
+In Vim9 script a mechanism very similar to the JavaScript import and export
+mechanism is supported. It is a variant to the existing `:source` command
+that works like one would expect:
+- Instead of making everything global by default, everything is script-local,
+ unless exported.
+- When importing a script the symbols that are imported are explicitly listed,
+ avoiding name conflicts and failures if functionality is added later.
+- The mechanism allows for writing a big, long script with a very clear API:
+ the exported function(s) and class(es).
+- By using relative paths loading can be much faster for an import inside of a
+ package, no need to search many directories.
+- Once an import has been used, it can be cached and loading it again can be
+ avoided.
+- The Vim-specific use of "s:" to make things script-local can be dropped.
+
+When sourcing a Vim9 script from a legacy script, only the items defined
+globally can be used, not the exported items. Alternatives considered:
+- All the exported items become available as script-local items. This makes
+ it uncontrollable what items get defined and likely soon leads to trouble.
+- Use the exported items and make them global. Disadvantage is that it's then
+ not possible to avoid name clashes in the global namespace.
+- Completely disallow sourcing a Vim9 script, require using `:import`. That
+ makes it difficult to use scripts for testing, or sourcing them from the
+ command line to try them out.
+Note that you can also use `:import` in legacy Vim script, see above.
+
+
+Compiling functions early ~
+
+Functions are compiled when called or when `:defcompile` is used. Why not
+compile them early, so that syntax and type errors are reported early?
+
+The functions can't be compiled right away when encountered, because there may
+be forward references to functions defined later. Consider defining functions
+A, B and C, where A calls B, B calls C, and C calls A again. It's impossible
+to reorder the functions to avoid forward references.
+
+An alternative would be to first scan through the file to locate items and
+figure out their type, so that forward references are found, and only then
+execute the script and compile the functions. This means the script has to be
+parsed twice, which is slower, and some conditions at the script level, such
+as checking if a feature is supported, are hard to use. An attempt was made
+to see if it works, but it turned out to be impossible to make work nicely.
+
+It would be possible to compile all the functions at the end of the script.
+The drawback is that if a function never gets called, the overhead of
+compiling it counts anyway. Since startup speed is very important, in most
+cases it's better to do it later and accept that syntax and type errors are
+only reported then. In case these errors should be found early, e.g. when
+testing, the `:defcompile` command will help out.
+
+
+Why not use an embedded language? ~
+
+Vim supports interfaces to Perl, Python, Lua, Tcl and a few others. But
+these interfaces have never become widely used, for various reasons. When
+Vim9 was designed a decision was made to make these interfaces lower priority
+and concentrate on Vim script.
+
+Still, plugin writers may find other languages more familiar, want to use
+existing libraries or see a performance benefit. We encourage plugin authors
+to write code in any language and run it as an external tool, using jobs and
+channels. We can try to make this easier somehow.
+
+Using an external tool also has disadvantages. An alternative is to convert
+the tool into Vim script. For that to be possible without too much
+translation, and keeping the code fast at the same time, the constructs of the
+tool need to be supported. Since most languages support classes the lack of
+support for classes in Vim is then a problem.
+
+
+Classes ~
+
+Vim supports a kind-of object oriented programming by adding methods to a
+dictionary. With some care this can be made to work, but it does not look
+like real classes. On top of that, it's quite slow, because of the use of
+dictionaries.
+
+The support of classes in Vim9 script is a "minimal common functionality" of
+class support in most languages. It works much like Java, which is the most
+popular programming language.
+
+
+
+ vim:tw=78:ts=8:noet:ft=help:norl: