blob: 0dae57debc8c6d77d54e6f66e62f7eb7a7946c3f [file] [log] [blame]
Hirohito Higashifbe4a8f2025-04-27 15:28:30 +02001*vim9.txt* For Vim version 9.1. Last change: 2025 Apr 27
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002
3
4 VIM REFERENCE MANUAL by Bram Moolenaar
5
6
Bram Moolenaardcc58e02020-12-28 20:53:21 +01007Vim9 script commands and expressions. *Vim9* *vim9*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01008
9Most expression help is in |eval.txt|. This file is about the new syntax and
10features in Vim9 script.
11
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010012
13
Bram Moolenaar7e6a5152021-01-02 16:39:53 +0100141. What is Vim9 script? |Vim9-script|
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100152. Differences |vim9-differences|
163. New style functions |fast-functions|
174. Types |vim9-types|
185. Namespace, Import and Export |vim9script|
Bram Moolenaarc1c365c2022-12-04 20:13:24 +0000196. Classes and interfaces |vim9-classes|
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010020
219. Rationale |vim9-rationale|
22
23==============================================================================
24
Bram Moolenaar2b327002020-12-26 15:39:31 +0100251. What is Vim9 script? *Vim9-script*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010026
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020027Vim script has been growing over time, while preserving backwards
28compatibility. That means bad choices from the past often can't be changed
Bram Moolenaar73fef332020-06-21 22:12:03 +020029and compatibility with Vi restricts possible solutions. Execution is quite
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020030slow, each line is parsed every time it is executed.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010031
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020032The main goal of Vim9 script is to drastically improve performance. This is
33accomplished by compiling commands into instructions that can be efficiently
34executed. An increase in execution speed of 10 to 100 times can be expected.
35
36A secondary goal is to avoid Vim-specific constructs and get closer to
37commonly used programming languages, such as JavaScript, TypeScript and Java.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010038
39The performance improvements can only be achieved by not being 100% backwards
Bram Moolenaar8a3b8052022-06-26 12:21:15 +010040compatible. For example, making function arguments available in the "a:"
41dictionary adds quite a lot of overhead. In a Vim9 function this dictionary
42is not available. Other differences are more subtle, such as how errors are
43handled.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010044
45The Vim9 script syntax and semantics are used in:
46- a function defined with the `:def` command
47- a script file where the first command is `vim9script`
Bram Moolenaar1d59aa12020-09-19 18:50:13 +020048- an autocommand defined in the context of the above
Bram Moolenaar39f3b142021-02-14 12:57:36 +010049- a command prefixed with the `vim9cmd` command modifier
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010050
Bram Moolenaar82be4842021-01-11 19:40:15 +010051When using `:function` in a Vim9 script file the legacy syntax is used, with
52the highest |scriptversion|. However, this can be confusing and is therefore
53discouraged.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010054
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020055Vim9 script and legacy Vim script can be mixed. There is no requirement to
Bram Moolenaar1d59aa12020-09-19 18:50:13 +020056rewrite old scripts, they keep working as before. You may want to use a few
57`:def` functions for code that needs to be fast.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010058
Bram Moolenaara2baa732022-02-04 16:09:54 +000059:vim9[cmd] {cmd} *:vim9* *:vim9cmd* *E1164*
Bram Moolenaar5b1d6e92022-02-11 20:33:48 +000060 Evaluate and execute {cmd} using Vim9 script syntax and
61 semantics. Useful when typing a command and in a legacy
62 script or function.
Bram Moolenaar39f3b142021-02-14 12:57:36 +010063
Bram Moolenaara2baa732022-02-04 16:09:54 +000064:leg[acy] {cmd} *:leg* *:legacy* *E1189* *E1234*
Bram Moolenaar5b1d6e92022-02-11 20:33:48 +000065 Evaluate and execute {cmd} using legacy script syntax and
66 semantics. Only useful in a Vim9 script or a :def function.
Bram Moolenaar96cf4ba2021-04-24 14:15:41 +020067 Note that {cmd} cannot use local variables, since it is parsed
68 with legacy expression syntax.
69
Christian Brabandtbad95772024-05-31 14:58:26 +020070See some examples of Vim9 script at |52.6|.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010071==============================================================================
72
732. Differences from legacy Vim script *vim9-differences*
74
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020075Overview ~
Bram Moolenaara2baa732022-02-04 16:09:54 +000076 *E1146*
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020077Brief summary of the differences you will most often encounter when using Vim9
78script and `:def` functions; details are below:
79- Comments start with #, not ": >
Bram Moolenaar82be4842021-01-11 19:40:15 +010080 echo "hello" # comment
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020081- Using a backslash for line continuation is hardly ever needed: >
Bram Moolenaar82be4842021-01-11 19:40:15 +010082 echo "hello "
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020083 .. yourName
84 .. ", how are you?"
Bram Moolenaar5da36052021-12-27 15:39:57 +000085- White space is required in many places to improve readability.
Bram Moolenaarf10911e2022-01-29 22:20:48 +000086- Assign values without `:let` *E1126* , declare variables with `:var`: >
Bram Moolenaar82be4842021-01-11 19:40:15 +010087 var count = 0
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020088 count += 3
89- Constants can be declared with `:final` and `:const`: >
Bram Moolenaar63f32602022-06-09 20:45:54 +010090 final matches = [] # add to the list later
Bram Moolenaard58a3bf2020-09-28 21:48:16 +020091 const names = ['Betty', 'Peter'] # cannot be changed
92- `:final` cannot be used as an abbreviation of `:finally`.
93- Variables and functions are script-local by default.
94- Functions are declared with argument types and return type: >
95 def CallMe(count: number, message: string): bool
96- Call functions without `:call`: >
Bram Moolenaar82be4842021-01-11 19:40:15 +010097 writefile(['done'], 'file.txt')
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +000098- You cannot use old Ex commands:
99 `:Print`
100 `:append`
101 `:change`
102 `:d` directly followed by 'd' or 'p'.
103 `:insert`
104 `:k`
105 `:mode`
106 `:open`
107 `:s` with only flags
108 `:t`
Bram Moolenaarbe4e0162023-02-02 13:59:48 +0000109 `:xit`
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +0000110- Some commands, especially those used for flow control, cannot be shortened.
Bram Moolenaar9712ff12022-09-18 13:04:22 +0100111 E.g., `:throw` cannot be written as `:th`. *vim9-no-shorten*
Bram Moolenaar22863042021-10-16 15:23:36 +0100112- You cannot use curly-braces names.
Bram Moolenaard58a3bf2020-09-28 21:48:16 +0200113- A range before a command must be prefixed with a colon: >
Bram Moolenaar82be4842021-01-11 19:40:15 +0100114 :%s/this/that
Bram Moolenaar89a9c152021-08-29 21:55:35 +0200115- Executing a register with "@r" does not work, you can prepend a colon or use
116 `:exe`: >
Bram Moolenaar938ae282023-02-20 20:44:55 +0000117 :exe @a
Bram Moolenaar82be4842021-01-11 19:40:15 +0100118- Unless mentioned specifically, the highest |scriptversion| is used.
Bram Moolenaarfd31be22022-01-16 14:46:06 +0000119- When defining an expression mapping, the expression will be evaluated in the
120 context of the script where it was defined.
Bram Moolenaar10e8ff92023-06-10 21:40:39 +0100121- When indexing a string the index is counted in characters, not bytes:
122 |vim9-string-index|
123- Some possibly unexpected differences: |vim9-gotchas|.
Bram Moolenaard58a3bf2020-09-28 21:48:16 +0200124
125
Bram Moolenaar2c330432020-04-13 14:41:35 +0200126Comments starting with # ~
127
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +0200128In legacy Vim script comments start with double quote. In Vim9 script
129comments start with #. >
130 # declarations
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200131 var count = 0 # number of occurrences
Bram Moolenaar2c330432020-04-13 14:41:35 +0200132
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +0200133The reason is that a double quote can also be the start of a string. In many
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200134places, especially halfway through an expression with a line break, it's hard
135to tell what the meaning is, since both a string and a comment can be followed
136by arbitrary text. To avoid confusion only # comments are recognized. This
137is the same as in shell scripts and Python programs.
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +0200138
139In Vi # is a command to list text with numbers. In Vim9 script you can use
140`:number` for that. >
Bram Moolenaar2f0936c2022-01-08 21:51:59 +0000141 :101 number
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +0200142
143To improve readability there must be a space between a command and the #
Bram Moolenaar2b327002020-12-26 15:39:31 +0100144that starts a comment: >
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100145 var name = value # comment
146 var name = value# error!
Bram Moolenaara2baa732022-02-04 16:09:54 +0000147< *E1170*
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200148Do not start a comment with #{, it looks like the legacy dictionary literal
149and produces an error where this might be confusing. #{{ or #{{{ are OK,
150these can be used to start a fold.
151
Bram Moolenaar5ed11532022-07-06 13:18:11 +0100152When starting to read a script file Vim doesn't know it is |Vim9| script until
153the `vim9script` command is found. Until that point you would need to use
154legacy comments: >
155 " legacy comment
156 vim9script
157 # Vim9 comment
158
159That looks ugly, better put `vim9script` in the very first line: >
160 vim9script
161 # Vim9 comment
162
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100163In legacy Vim script # is also used for the alternate file name. In Vim9
164script you need to use %% instead. Instead of ## use %%% (stands for all
165arguments).
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200166
Bram Moolenaar2c330432020-04-13 14:41:35 +0200167
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100168Vim9 functions ~
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000169 *E1099*
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200170A function defined with `:def` is compiled. Execution is many times faster,
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200171often 10 to 100 times.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200172
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200173Many errors are already found when compiling, before the function is executed.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200174The syntax is strict, to enforce code that is easy to read and understand.
175
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200176Compilation is done when any of these is encountered:
Bram Moolenaar1b884a02020-12-10 21:11:27 +0100177- the first time the function is called
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200178- when the `:defcompile` command is encountered in the script after the
Bram Moolenaar207f0092020-08-30 17:20:20 +0200179 function was defined
180- `:disassemble` is used for the function.
181- a function that is compiled calls the function or uses it as a function
Bram Moolenaar89a9c152021-08-29 21:55:35 +0200182 reference (so that the argument and return types can be checked)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000183 *E1091* *E1191*
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200184If compilation fails it is not tried again on the next call, instead this
185error is given: "E1091: Function is not compiled: {name}".
Bram Moolenaar4c295022021-05-02 17:19:11 +0200186Compilation will fail when encountering a user command that has not been
187created yet. In this case you can call `execute()` to invoke it at runtime. >
188 def MyFunc()
189 execute('DefinedLater')
190 enddef
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200191
192`:def` has no options like `:function` does: "range", "abort", "dict" or
Bram Moolenaar1b884a02020-12-10 21:11:27 +0100193"closure". A `:def` function always aborts on an error (unless `:silent!` was
Bram Moolenaarfa3b7232021-12-24 13:18:38 +0000194used for the command or the error was caught a `:try` block), does not get a
Bram Moolenaar63f32602022-06-09 20:45:54 +0100195range passed, cannot be a "dict" function, and can always be a closure.
h-east08be9dd2024-12-23 10:11:25 +0100196 *vim9-no-dict-function* *E1182*
Bram Moolenaar10e8ff92023-06-10 21:40:39 +0100197You can use a Vim9 Class (|Vim9-class|) instead of a "dict function".
198You can also pass the dictionary explicitly: >
Bram Moolenaar63f32602022-06-09 20:45:54 +0100199 def DictFunc(self: dict<any>, arg: string)
200 echo self[arg]
Bram Moolenaar74235772021-06-12 14:53:05 +0200201 enddef
Bram Moolenaar46eea442022-03-30 10:51:39 +0100202 var ad = {item: 'value', func: DictFunc}
Bram Moolenaarcbaff5e2022-04-08 17:45:08 +0100203 ad.func(ad, 'item')
Bram Moolenaar74235772021-06-12 14:53:05 +0200204
Bram Moolenaar34cc7d82021-09-21 20:09:51 +0200205You can call a legacy dict function though: >
206 func Legacy() dict
207 echo self.value
208 endfunc
209 def CallLegacy()
210 var d = {func: Legacy, value: 'text'}
211 d.func()
212 enddef
Bram Moolenaara2baa732022-02-04 16:09:54 +0000213< *E1096* *E1174* *E1175*
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200214The argument types and return type need to be specified. The "any" type can
215be used, type checking will then be done at runtime, like with legacy
216functions.
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000217 *E1106*
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200218Arguments are accessed by name, without "a:", just like any other language.
219There is no "a:" dictionary or "a:000" list.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000220 *vim9-variable-arguments* *E1055* *E1160* *E1180*
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200221Variable arguments are defined as the last argument, with a name and have a
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200222list type, similar to TypeScript. For example, a list of numbers: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200223 def MyFunc(...itemlist: list<number>)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100224 for item in itemlist
225 ...
226
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200227When a function argument is optional (it has a default value) passing `v:none`
228as the argument results in using the default value. This is useful when you
229want to specify a value for an argument that comes after an argument that
230should use its default value. Example: >
Bram Moolenaar22863042021-10-16 15:23:36 +0100231 def MyFunc(one = 'one', last = 'last')
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200232 ...
233 enddef
234 MyFunc(v:none, 'LAST') # first argument uses default value 'one'
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200235<
Bram Moolenaara2baa732022-02-04 16:09:54 +0000236 *vim9-ignored-argument* *E1181*
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200237The argument "_" (an underscore) can be used to ignore the argument. This is
238most useful in callbacks where you don't need it, but do need to give an
239argument to match the call. E.g. when using map() two arguments are passed,
240the key and the value, to ignore the key: >
Bram Moolenaar63f32602022-06-09 20:45:54 +0100241 map(numberList, (_, v) => v * 2)
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200242There is no error for using the "_" argument multiple times. No type needs to
243be given.
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200244
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100245
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200246Functions and variables are script-local by default ~
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200247 *vim9-scopes*
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200248When using `:function` or `:def` to specify a new function at the script level
Bram Moolenaar92f645b2022-02-11 13:29:40 +0000249in a Vim9 script, the function is local to the script. Like prefixing "s:" in
250legacy script. To define a global function or variable the "g:" prefix must
251be used. For functions in a script that is to be imported and in an autoload
Bram Moolenaar63f32602022-06-09 20:45:54 +0100252script "export" needs to be used for those to be used elsewhere. >
Bram Moolenaarea2d8d22020-07-29 22:11:05 +0200253 def ThisFunction() # script-local
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200254 def g:ThatFunction() # global
Bram Moolenaar9da17d72022-02-09 21:50:44 +0000255 export def Function() # for import and import autoload
Bram Moolenaar6f4754b2022-01-23 12:07:04 +0000256< *E1058* *E1075*
Bram Moolenaar2bb26582020-10-03 22:52:39 +0200257When using `:function` or `:def` to specify a nested function inside a `:def`
Bram Moolenaar47003982021-12-05 21:54:04 +0000258function and no namespace was given, this nested function is local to the code
Bram Moolenaarc51cf032022-02-26 12:25:45 +0000259block it is defined in. It cannot be used in `function()` with a string
260argument, pass the function reference itself: >
261 def Outer()
262 def Inner()
263 echo 'inner'
264 enddef
265 var Fok = function(Inner) # OK
266 var Fbad = function('Inner') # does not work
267
Bram Moolenaar63f32602022-06-09 20:45:54 +0100268Detail: this is because "Inner" will actually become a function reference to a
269function with a generated name.
270
271It is not possible to define a script-local function in a function. You can
Bram Moolenaarbe4e0162023-02-02 13:59:48 +0000272define a local function and assign it to a script-local Funcref (it must have
Bram Moolenaar63f32602022-06-09 20:45:54 +0100273been declared at the script level). It is possible to define a global
274function by using the "g:" prefix.
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200275
276When referring to a function and no "s:" or "g:" prefix is used, Vim will
Bram Moolenaar13106602020-10-04 16:06:05 +0200277search for the function:
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +0200278- in the function scope, in block scopes
Bram Moolenaar63f32602022-06-09 20:45:54 +0100279- in the script scope
280
281Imported functions are found with the prefix from the `:import` command.
Bram Moolenaar13106602020-10-04 16:06:05 +0200282
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200283Since a script-local function reference can be used without "s:" the name must
Bram Moolenaardad44732021-03-31 20:07:33 +0200284start with an upper case letter even when using the "s:" prefix. In legacy
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200285script "s:funcref" could be used, because it could not be referred to with
286"funcref". In Vim9 script it can, therefore "s:Funcref" must be used to avoid
287that the name interferes with builtin functions.
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100288 *vim9-s-namespace* *E1268*
Bram Moolenaar92f645b2022-02-11 13:29:40 +0000289The use of the "s:" prefix is not supported at the Vim9 script level. All
290functions and variables without a prefix are script-local.
Bram Moolenaarafa048f2022-02-22 20:43:36 +0000291
292In :def functions the use of "s:" depends on the script: Script-local
293variables and functions in a legacy script do use "s:", while in a Vim9 script
294they do not use "s:". This matches what you see in the rest of the file.
295
Bram Moolenaar92f645b2022-02-11 13:29:40 +0000296In legacy functions the use of "s:" for script items is required, as before.
Bram Moolenaar63f32602022-06-09 20:45:54 +0100297No matter if the script is Vim9 or legacy.
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200298
Bram Moolenaar13106602020-10-04 16:06:05 +0200299In all cases the function must be defined before used. That is when it is
Bram Moolenaarcb80aa22020-10-26 21:12:46 +0100300called, when `:defcompile` causes it to be compiled, or when code that calls
301it is being compiled (to figure out the return type).
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200302
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200303The result is that functions and variables without a namespace can usually be
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200304found in the script, either defined there or imported. Global functions and
Bram Moolenaar63f32602022-06-09 20:45:54 +0100305variables could be defined anywhere (good luck finding out where! You can
306often see where it was last set using |:verbose|).
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000307 *E1102*
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200308Global functions can still be defined and deleted at nearly any time. In
Bram Moolenaar2cfb4a22020-05-07 18:56:00 +0200309Vim9 script script-local functions are defined once when the script is sourced
Bram Moolenaar63f32602022-06-09 20:45:54 +0100310and cannot be deleted or replaced by itself (it can be by reloading the
311script).
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200312
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100313When compiling a function and a function call is encountered for a function
314that is not (yet) defined, the |FuncUndefined| autocommand is not triggered.
315You can use an autoload function if needed, or call a legacy function and have
316|FuncUndefined| triggered there.
317
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200318
Bram Moolenaar2b327002020-12-26 15:39:31 +0100319Reloading a Vim9 script clears functions and variables by default ~
Bram Moolenaara2baa732022-02-04 16:09:54 +0000320 *vim9-reload* *E1149* *E1150*
Bram Moolenaar2b327002020-12-26 15:39:31 +0100321When loading a legacy Vim script a second time nothing is removed, the
Bram Moolenaar30ab04e2022-05-14 13:33:50 +0100322commands will replace existing variables and functions, create new ones, and
323leave removed things hanging around.
Bram Moolenaar2b327002020-12-26 15:39:31 +0100324
325When loading a Vim9 script a second time all existing script-local functions
326and variables are deleted, thus you start with a clean slate. This is useful
327if you are developing a plugin and want to try a new version. If you renamed
328something you don't have to worry about the old name still hanging around.
329
330If you do want to keep items, use: >
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100331 vim9script noclear
Bram Moolenaar2b327002020-12-26 15:39:31 +0100332
333You want to use this in scripts that use a `finish` command to bail out at
Bram Moolenaar944697a2022-02-20 19:48:20 +0000334some point when loaded again. E.g. when a buffer local option is set to a
335function, the function does not need to be defined more than once: >
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100336 vim9script noclear
Bram Moolenaar2b327002020-12-26 15:39:31 +0100337 setlocal completefunc=SomeFunc
Bram Moolenaar944697a2022-02-20 19:48:20 +0000338 if exists('*SomeFunc')
Bram Moolenaar9da17d72022-02-09 21:50:44 +0000339 finish
340 endif
Bram Moolenaar944697a2022-02-20 19:48:20 +0000341 def SomeFunc()
Bram Moolenaar2b327002020-12-26 15:39:31 +0100342 ....
343
Bram Moolenaar2b327002020-12-26 15:39:31 +0100344
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200345Variable declarations with :var, :final and :const ~
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +0000346 *vim9-declaration* *:var* *E1079*
Dominique Pellee764d1b2023-03-12 21:20:59 +0000347 *E1017* *E1020* *E1054* *E1087* *E1124*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200348Local variables need to be declared with `:var`. Local constants need to be
349declared with `:final` or `:const`. We refer to both as "variables" in this
350section.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100351
352Variables can be local to a script, function or code block: >
353 vim9script
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200354 var script_var = 123
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100355 def SomeFunc()
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200356 var func_var = script_var
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100357 if cond
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200358 var block_var = func_var
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100359 ...
360
361The variables are only visible in the block where they are defined and nested
362blocks. Once the block ends the variable is no longer accessible: >
363 if cond
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200364 var inner = 5
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100365 else
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200366 var inner = 0
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100367 endif
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200368 echo inner # Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100369
370The declaration must be done earlier: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200371 var inner: number
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100372 if cond
373 inner = 5
374 else
375 inner = 0
376 endif
377 echo inner
Bram Moolenaar63f32602022-06-09 20:45:54 +0100378
379Although this is shorter and faster for simple values: >
380 var inner = 0
381 if cond
382 inner = 5
383 endif
384 echo inner
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000385< *E1025* *E1128*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200386To intentionally hide a variable from code that follows, a block can be
387used: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100388 {
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200389 var temp = 'temp'
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100390 ...
391 }
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200392 echo temp # Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100393
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200394This is especially useful in a user command: >
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200395 command -range Rename {
Bram Moolenaar6aa57292021-08-14 21:25:52 +0200396 var save = @a
397 @a = 'some expression'
398 echo 'do something with ' .. @a
399 @a = save
400 }
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200401
402And with autocommands: >
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200403 au BufWritePre *.go {
Bram Moolenaar6aa57292021-08-14 21:25:52 +0200404 var save = winsaveview()
405 silent! exe ':%! some formatting command'
406 winrestview(save)
407 }
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200408
409Although using a :def function probably works better.
Bram Moolenaar46eea442022-03-30 10:51:39 +0100410
Bram Moolenaara2baa732022-02-04 16:09:54 +0000411 *E1022* *E1103* *E1130* *E1131* *E1133*
Dominique Pelle7765f5c2022-04-10 11:26:53 +0100412 *E1134*
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200413Declaring a variable with a type but without an initializer will initialize to
Bram Moolenaar1f318c62021-12-26 18:09:31 +0000414false (for bool), empty (for string, list, dict, etc.) or zero (for number,
415any, etc.). This matters especially when using the "any" type, the value will
Bram Moolenaar46eea442022-03-30 10:51:39 +0100416default to the number zero. For example, when declaring a list, items can be
417added: >
418 var myList: list<number>
419 myList->add(7)
420
421Initializing a variable to a null value, e.g. `null_list`, differs from not
422initializing the variable. This throws an error: >
423 var myList = null_list
424 myList->add(7) # E1130: Cannot add to null list
425
426< *E1016* *E1052* *E1066*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200427In Vim9 script `:let` cannot be used. An existing variable is assigned to
428without any command. The same for global, window, tab, buffer and Vim
Bram Moolenaar5da36052021-12-27 15:39:57 +0000429variables, because they are not really declared. Those can also be deleted
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200430with `:unlet`.
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +0000431 *E1065*
432You cannot use `:va` to declare a variable, it must be written with the full
433name `:var`. Just to make sure it is easy to read.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000434 *E1178*
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200435`:lockvar` does not work on local variables. Use `:const` and `:final`
436instead.
437
Bram Moolenaar6aa57292021-08-14 21:25:52 +0200438The `exists()` and `exists_compiled()` functions do not work on local variables
439or arguments.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000440 *E1006* *E1041* *E1167* *E1168* *E1213*
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100441Variables, functions and function arguments cannot shadow previously defined
442or imported variables and functions in the same script file.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100443Variables may shadow Ex commands, rename the variable if needed.
444
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200445Global variables must be prefixed with "g:", also at the script level. >
Bram Moolenaard1caa942020-04-10 22:10:56 +0200446 vim9script
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200447 var script_local = 'text'
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200448 g:global = 'value'
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200449 var Funcref = g:ThatFunction
Bram Moolenaard1caa942020-04-10 22:10:56 +0200450
Bram Moolenaarc4573eb2022-01-31 15:40:56 +0000451Global functions must be prefixed with "g:": >
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200452 vim9script
453 def g:GlobalFunc(): string
454 return 'text'
455 enddef
Bram Moolenaarc4573eb2022-01-31 15:40:56 +0000456 echo g:GlobalFunc()
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200457The "g:" prefix is not needed for auto-load functions.
458
Bram Moolenaar6aa57292021-08-14 21:25:52 +0200459 *vim9-function-defined-later*
460Although global functions can be called without the "g:" prefix, they must
461exist when compiled. By adding the "g:" prefix the function can be defined
462later. Example: >
463 def CallPluginFunc()
464 if exists('g:loaded_plugin')
465 g:PluginFunc()
466 endif
467 enddef
468
Bram Moolenaarb79ee0c2022-01-01 12:17:00 +0000469If you do it like this, you get an error at compile time that "PluginFunc"
470does not exist, even when "g:loaded_plugin" does not exist: >
Bram Moolenaar6aa57292021-08-14 21:25:52 +0200471 def CallPluginFunc()
472 if exists('g:loaded_plugin')
473 PluginFunc() # Error - function not found
474 endif
475 enddef
476
477You can use exists_compiled() to avoid the error, but then the function would
478not be called, even when "g:loaded_plugin" is defined later: >
479 def CallPluginFunc()
480 if exists_compiled('g:loaded_plugin')
481 PluginFunc() # Function may never be called
482 endif
483 enddef
484
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200485Since `&opt = value` is now assigning a value to option "opt", ":&" cannot be
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100486used to repeat a `:substitute` command.
Bram Moolenaar56994d22021-04-17 16:31:09 +0200487 *vim9-unpack-ignore*
Bram Moolenaarf93bbd02021-04-10 22:35:43 +0200488For an unpack assignment the underscore can be used to ignore a list item,
489similar to how a function argument can be ignored: >
490 [a, _, c] = theList
Bram Moolenaar56994d22021-04-17 16:31:09 +0200491To ignore any remaining items: >
Bram Moolenaarf93bbd02021-04-10 22:35:43 +0200492 [a, b; _] = longList
Bram Moolenaar944697a2022-02-20 19:48:20 +0000493< *E1163* *E1080*
Bram Moolenaarf93bbd02021-04-10 22:35:43 +0200494Declaring more than one variable at a time, using the unpack notation, is
Bram Moolenaarab36e6a2021-11-30 16:14:49 +0000495possible. Each variable can have a type or infer it from the value: >
496 var [v1: number, v2] = GetValues()
497Use this only when there is a list with values, declaring one variable per
498line is much easier to read and change later.
Bram Moolenaarf93bbd02021-04-10 22:35:43 +0200499
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200500
501Constants ~
502 *vim9-const* *vim9-final*
503How constants work varies between languages. Some consider a variable that
504can't be assigned another value a constant. JavaScript is an example. Others
505also make the value immutable, thus when a constant uses a list, the list
506cannot be changed. In Vim9 we can use both.
Bram Moolenaarf269eab2022-10-03 18:04:35 +0100507 *E1021* *E1307*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200508`:const` is used for making both the variable and the value a constant. Use
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200509this for composite structures that you want to make sure will not be modified.
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200510Example: >
511 const myList = [1, 2]
512 myList = [3, 4] # Error!
513 myList[0] = 9 # Error!
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100514 myList->add(3) # Error!
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000515< *:final* *E1125*
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200516`:final` is used for making only the variable a constant, the value can be
517changed. This is well known from Java. Example: >
518 final myList = [1, 2]
519 myList = [3, 4] # Error!
520 myList[0] = 9 # OK
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100521 myList->add(3) # OK
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200522
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200523It is common to write constants as ALL_CAPS, but you don't have to.
524
525The constant only applies to the value itself, not what it refers to. >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200526 final females = ["Mary"]
527 const NAMES = [["John", "Peter"], females]
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200528 NAMES[0] = ["Jack"] # Error!
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200529 NAMES[0][0] = "Jack" # Error!
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200530 NAMES[1] = ["Emma"] # Error!
Bram Moolenaar82be4842021-01-11 19:40:15 +0100531 NAMES[1][0] = "Emma" # OK, now females[0] == "Emma"
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200532
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100533
534Omitting :call and :eval ~
Bram Moolenaara2baa732022-02-04 16:09:54 +0000535 *E1190*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100536Functions can be called without `:call`: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200537 writefile(lines, 'file')
Bram Moolenaar560979e2020-02-04 22:53:05 +0100538Using `:call` is still possible, but this is discouraged.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100539
540A method call without `eval` is possible, so long as the start is an
Bram Moolenaar0289a092021-03-14 18:40:19 +0100541identifier or can't be an Ex command. For a function either "(" or "->" must
542be following, without a line break. Examples: >
Bram Moolenaarae616492020-07-28 20:07:27 +0200543 myList->add(123)
544 g:myList->add(123)
545 [1, 2, 3]->Process()
Bram Moolenaar2bede172020-11-19 18:53:18 +0100546 {a: 1, b: 2}->Process()
Bram Moolenaarae616492020-07-28 20:07:27 +0200547 "foobar"->Process()
548 ("foobar")->Process()
549 'foobar'->Process()
550 ('foobar')->Process()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100551
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200552In the rare case there is ambiguity between a function name and an Ex command,
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200553prepend ":" to make clear you want to use the Ex command. For example, there
554is both the `:substitute` command and the `substitute()` function. When the
555line starts with `substitute(` this will use the function. Prepend a colon to
556use the command instead: >
Bram Moolenaar0c6ceaf2020-02-22 18:36:32 +0100557 :substitute(pattern (replacement (
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100558
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200559If the expression starts with "!" this is interpreted as a shell command, not
560negation of a condition. Thus this is a shell command: >
561 !shellCommand->something
Bram Moolenaar89a9c152021-08-29 21:55:35 +0200562Put the expression in parentheses to use the "!" for negation: >
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200563 (!expression)->Method()
564
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100565Note that while variables need to be defined before they can be used,
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200566functions can be called before being defined. This is required to allow
567for cyclic dependencies between functions. It is slightly less efficient,
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100568since the function has to be looked up by name. And a typo in the function
Bram Moolenaarae616492020-07-28 20:07:27 +0200569name will only be found when the function is called.
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100570
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100571
Bram Moolenaard1caa942020-04-10 22:10:56 +0200572Omitting function() ~
573
574A user defined function can be used as a function reference in an expression
575without `function()`. The argument types and return type will then be checked.
576The function must already have been defined. >
577
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200578 var Funcref = MyFunction
Bram Moolenaard1caa942020-04-10 22:10:56 +0200579
580When using `function()` the resulting type is "func", a function with any
Bram Moolenaar90df4b92021-07-07 20:26:08 +0200581number of arguments and any return type (including void). The function can be
Bram Moolenaarfa3b7232021-12-24 13:18:38 +0000582defined later if the argument is in quotes.
Bram Moolenaard1caa942020-04-10 22:10:56 +0200583
584
Bram Moolenaar2b327002020-12-26 15:39:31 +0100585Lambda using => instead of -> ~
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200586 *vim9-lambda*
Bram Moolenaar65c44152020-12-24 15:14:01 +0100587In legacy script there can be confusion between using "->" for a method call
588and for a lambda. Also, when a "{" is found the parser needs to figure out if
589it is the start of a lambda or a dictionary, which is now more complicated
590because of the use of argument types.
591
592To avoid these problems Vim9 script uses a different syntax for a lambda,
Bram Moolenaar74235772021-06-12 14:53:05 +0200593which is similar to JavaScript: >
Bram Moolenaar65c44152020-12-24 15:14:01 +0100594 var Lambda = (arg) => expression
Bram Moolenaara2baa732022-02-04 16:09:54 +0000595 var Lambda = (arg): type => expression
596< *E1157*
Bram Moolenaar2b327002020-12-26 15:39:31 +0100597No line break is allowed in the arguments of a lambda up to and including the
Bram Moolenaar4d8f4762021-06-27 15:18:56 +0200598"=>" (so that Vim can tell the difference between an expression in parentheses
Bram Moolenaar2346a632021-06-13 19:02:49 +0200599and lambda arguments). This is OK: >
Bram Moolenaar65c44152020-12-24 15:14:01 +0100600 filter(list, (k, v) =>
601 v > 0)
602This does not work: >
603 filter(list, (k, v)
604 => v > 0)
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100605This also does not work: >
Bram Moolenaar65c44152020-12-24 15:14:01 +0100606 filter(list, (k,
607 v) => v > 0)
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100608But you can use a backslash to concatenate the lines before parsing: >
609 filter(list, (k,
610 \ v)
611 \ => v > 0)
Bram Moolenaara2baa732022-02-04 16:09:54 +0000612< *vim9-lambda-arguments* *E1172*
Bram Moolenaar962c43b2021-04-10 17:18:09 +0200613In legacy script a lambda could be called with any number of extra arguments,
614there was no way to warn for not using them. In Vim9 script the number of
615arguments must match. If you do want to accept any arguments, or any further
616arguments, use "..._", which makes the function accept
617|vim9-variable-arguments|. Example: >
618 var Callback = (..._) => 'anything'
619 echo Callback(1, 2, 3) # displays "anything"
620
Bram Moolenaara2baa732022-02-04 16:09:54 +0000621< *inline-function* *E1171*
Bram Moolenaar65c44152020-12-24 15:14:01 +0100622Additionally, a lambda can contain statements in {}: >
623 var Lambda = (arg) => {
624 g:was_called = 'yes'
625 return expression
626 }
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200627This can be useful for a timer, for example: >
628 var count = 0
Bram Moolenaar938ae282023-02-20 20:44:55 +0000629 var timer = timer_start(500, (_) => {
Bram Moolenaar130cbfc2021-04-07 21:07:20 +0200630 count += 1
631 echom 'Handler called ' .. count
632 }, {repeat: 3})
633
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200634The ending "}" must be at the start of a line. It can be followed by other
635characters, e.g.: >
636 var d = mapnew(dict, (k, v): string => {
637 return 'value'
638 })
639No command can follow the "{", only a comment can be used there.
640
Bram Moolenaar6f4754b2022-01-23 12:07:04 +0000641 *command-block* *E1026*
Bram Moolenaar259f4432021-12-17 12:45:22 +0000642The block can also be used for defining a user command. Inside the block Vim9
643syntax will be used.
644
Yegappan Lakshmanane74cad32024-04-12 18:48:35 +0200645This is an example of using here-docs: >
646 com SomeCommand {
647 g:someVar =<< trim eval END
648 ccc
649 ddd
650 END
651 }
652
Bram Moolenaar0e6adf82021-12-16 14:41:10 +0000653If the statements include a dictionary, its closing bracket must not be
654written at the start of a line. Otherwise, it would be parsed as the end of
655the block. This does not work: >
656 command NewCommand {
Bram Moolenaar259f4432021-12-17 12:45:22 +0000657 g:mydict = {
Bram Moolenaar0e6adf82021-12-16 14:41:10 +0000658 'key': 'value',
659 } # ERROR: will be recognized as the end of the block
660 }
661Put the '}' after the last item to avoid this: >
662 command NewCommand {
Bram Moolenaar259f4432021-12-17 12:45:22 +0000663 g:mydict = {
Bram Moolenaar0e6adf82021-12-16 14:41:10 +0000664 'key': 'value' }
665 }
666
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +0200667Rationale: The "}" cannot be after a command because it would require parsing
668the commands to find it. For consistency with that no command can follow the
669"{". Unfortunately this means using "() => { command }" does not work, line
670breaks are always required.
Bram Moolenaar65c44152020-12-24 15:14:01 +0100671
Bram Moolenaare0e39172021-01-25 21:14:57 +0100672 *vim9-curly*
Bram Moolenaar2b327002020-12-26 15:39:31 +0100673To avoid the "{" of a dictionary literal to be recognized as a statement block
Bram Moolenaar9faec4e2021-02-27 16:38:07 +0100674wrap it in parentheses: >
Bram Moolenaar2b327002020-12-26 15:39:31 +0100675 var Lambda = (arg) => ({key: 42})
Bram Moolenaar65c44152020-12-24 15:14:01 +0100676
Bram Moolenaare0e39172021-01-25 21:14:57 +0100677Also when confused with the start of a command block: >
678 ({
679 key: value
680 })->method()
681
Bram Moolenaar65c44152020-12-24 15:14:01 +0100682
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200683Automatic line continuation ~
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000684 *vim9-line-continuation* *E1097*
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200685In many cases it is obvious that an expression continues on the next line. In
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100686those cases there is no need to prefix the line with a backslash (see
687|line-continuation|). For example, when a list spans multiple lines: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200688 var mylist = [
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200689 'one',
690 'two',
691 ]
Bram Moolenaare6085c52020-04-12 20:19:16 +0200692And when a dict spans multiple lines: >
Bram Moolenaar2bede172020-11-19 18:53:18 +0100693 var mydict = {
Bram Moolenaare6085c52020-04-12 20:19:16 +0200694 one: 1,
695 two: 2,
696 }
Bram Moolenaar74235772021-06-12 14:53:05 +0200697With a function call: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200698 var result = Func(
Bram Moolenaare6085c52020-04-12 20:19:16 +0200699 arg1,
700 arg2
701 )
702
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200703For binary operators in expressions not in [], {} or () a line break is
704possible just before or after the operator. For example: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200705 var text = lead
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200706 .. middle
707 .. end
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200708 var total = start +
Bram Moolenaar82be4842021-01-11 19:40:15 +0100709 end -
Bram Moolenaar9c7e6dd2020-04-12 20:55:20 +0200710 correction
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200711 var result = positive
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200712 ? PosFunc(arg)
713 : NegFunc(arg)
Bram Moolenaar9c7e6dd2020-04-12 20:55:20 +0200714
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200715For a method call using "->" and a member using a dot, a line break is allowed
716before it: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200717 var result = GetBuilder()
Bram Moolenaar73fef332020-06-21 22:12:03 +0200718 ->BuilderSetWidth(333)
719 ->BuilderSetHeight(777)
720 ->BuilderBuild()
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200721 var result = MyDict
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200722 .member
Bram Moolenaar73fef332020-06-21 22:12:03 +0200723
Bram Moolenaardcc58e02020-12-28 20:53:21 +0100724For commands that have an argument that is a list of commands, the | character
725at the start of the line indicates line continuation: >
726 autocmd BufNewFile *.match if condition
727 | echo 'match'
728 | endif
729
Bram Moolenaar22863042021-10-16 15:23:36 +0100730Note that this means that in heredoc the first line cannot start with a bar: >
Bram Moolenaar74235772021-06-12 14:53:05 +0200731 var lines =<< trim END
732 | this doesn't work
733 END
734Either use an empty line at the start or do not use heredoc. Or temporarily
735add the "C" flag to 'cpoptions': >
736 set cpo+=C
737 var lines =<< trim END
Bram Moolenaar22863042021-10-16 15:23:36 +0100738 | this works
Bram Moolenaar74235772021-06-12 14:53:05 +0200739 END
740 set cpo-=C
741If the heredoc is inside a function 'cpoptions' must be set before :def and
742restored after the :enddef.
743
744In places where line continuation with a backslash is still needed, such as
Bram Moolenaar90df4b92021-07-07 20:26:08 +0200745splitting up a long Ex command, comments can start with '#\ ': >
746 syn region Text
Bram Moolenaar74235772021-06-12 14:53:05 +0200747 \ start='foo'
748 #\ comment
749 \ end='bar'
Bram Moolenaar90df4b92021-07-07 20:26:08 +0200750Like with legacy script '"\ ' is used. This is also needed when line
751continuation is used without a backslash and a line starts with a bar: >
752 au CursorHold * echom 'BEFORE bar'
753 #\ some comment
754 | echom 'AFTER bar'
755<
756 *E1050*
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200757To make it possible for the operator at the start of the line to be
Bram Moolenaar74235772021-06-12 14:53:05 +0200758recognized, it is required to put a colon before a range. This example will
Bram Moolenaarbe4e0162023-02-02 13:59:48 +0000759add "start" and "print": >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200760 var result = start
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200761 + print
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200762Like this: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200763 var result = start + print
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200764
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200765This will assign "start" and print a line: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +0200766 var result = start
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200767 :+ print
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200768
Bram Moolenaar6f4754b2022-01-23 12:07:04 +0000769After the range an Ex command must follow. Without the colon you can call a
770function without `:call`, but after a range you do need it: >
771 MyFunc()
772 :% call MyFunc()
773
Bram Moolenaar23515b42020-11-29 14:36:24 +0100774Note that the colon is not required for the |+cmd| argument: >
775 edit +6 fname
776
Bram Moolenaar5e774c72020-04-12 21:53:00 +0200777It is also possible to split a function header over multiple lines, in between
778arguments: >
779 def MyFunc(
780 text: string,
781 separator = '-'
782 ): string
783
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100784Since a continuation line cannot be easily recognized the parsing of commands
Bram Moolenaar65c44152020-12-24 15:14:01 +0100785has been made stricter. E.g., because of the error in the first line, the
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100786second line is seen as a separate command: >
787 popup_create(some invalid expression, {
788 exit_cb: Func})
789Now "exit_cb: Func})" is actually a valid command: save any changes to the
790file "_cb: Func})" and exit. To avoid this kind of mistake in Vim9 script
791there must be white space between most command names and the argument.
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000792*E1144*
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100793
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100794However, the argument of a command that is a command won't be recognized. For
795example, after "windo echo expr" a line break inside "expr" will not be seen.
796
Bram Moolenaar4072ba52020-12-23 13:56:35 +0100797
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200798Notes:
799- "enddef" cannot be used at the start of a continuation line, it ends the
800 current function.
801- No line break is allowed in the LHS of an assignment. Specifically when
802 unpacking a list |:let-unpack|. This is OK: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200803 [var1, var2] =
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200804 Func()
805< This does not work: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200806 [var1,
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200807 var2] =
808 Func()
809- No line break is allowed in between arguments of an `:echo`, `:execute` and
810 similar commands. This is OK: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200811 echo [1,
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200812 2] [3,
813 4]
814< This does not work: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200815 echo [1, 2]
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200816 [3, 4]
Bram Moolenaar74235772021-06-12 14:53:05 +0200817- In some cases it is difficult for Vim to parse a command, especially when
Bram Moolenaarbe4e0162023-02-02 13:59:48 +0000818 commands are used as an argument to another command, such as `:windo`. In
Bram Moolenaar74235772021-06-12 14:53:05 +0200819 those cases the line continuation with a backslash has to be used.
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200820
Bram Moolenaar4c295022021-05-02 17:19:11 +0200821
822White space ~
Bram Moolenaara2baa732022-02-04 16:09:54 +0000823 *E1004* *E1068* *E1069* *E1074* *E1127* *E1202*
Bram Moolenaar4c295022021-05-02 17:19:11 +0200824Vim9 script enforces proper use of white space. This is no longer allowed: >
825 var name=234 # Error!
826 var name= 234 # Error!
827 var name =234 # Error!
828There must be white space before and after the "=": >
829 var name = 234 # OK
830White space must also be put before the # that starts a comment after a
831command: >
832 var name = 234# Error!
833 var name = 234 # OK
834
835White space is required around most operators.
836
837White space is required in a sublist (list slice) around the ":", except at
838the start and end: >
Bram Moolenaar938ae282023-02-20 20:44:55 +0000839 otherlist = mylist[v : count] # v:count has a different meaning
Bram Moolenaar4c295022021-05-02 17:19:11 +0200840 otherlist = mylist[:] # make a copy of the List
841 otherlist = mylist[v :]
842 otherlist = mylist[: v]
843
844White space is not allowed:
845- Between a function name and the "(": >
846 Func (arg) # Error!
847 Func
848 \ (arg) # Error!
849 Func
850 (arg) # Error!
851 Func(arg) # OK
852 Func(
853 arg) # OK
854 Func(
855 arg # OK
856 )
Bram Moolenaara2baa732022-02-04 16:09:54 +0000857< *E1205*
Bram Moolenaar89a9c152021-08-29 21:55:35 +0200858White space is not allowed in a `:set` command between the option name and a
859following "&", "!", "<", "=", "+=", "-=" or "^=".
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +0200860
Bram Moolenaar4c295022021-05-02 17:19:11 +0200861
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100862No curly braces expansion ~
863
864|curly-braces-names| cannot be used.
865
866
Bram Moolenaara2baa732022-02-04 16:09:54 +0000867Command modifiers are not ignored ~
868 *E1176*
869Using a command modifier for a command that does not use it gives an error.
Bram Moolenaar2ecbe532022-07-29 21:36:21 +0100870 *E1082*
871Also, using a command modifier without a following command is now an error.
Bram Moolenaara2baa732022-02-04 16:09:54 +0000872
873
Bram Moolenaar2bede172020-11-19 18:53:18 +0100874Dictionary literals ~
Bram Moolenaar6f4754b2022-01-23 12:07:04 +0000875 *vim9-literal-dict* *E1014*
Bram Moolenaar2bede172020-11-19 18:53:18 +0100876Traditionally Vim has supported dictionary literals with a {} syntax: >
877 let dict = {'key': value}
878
Bram Moolenaarc5e6a712020-12-04 19:12:14 +0100879Later it became clear that using a simple text key is very common, thus
880literal dictionaries were introduced in a backwards compatible way: >
Bram Moolenaar2bede172020-11-19 18:53:18 +0100881 let dict = #{key: value}
882
Bram Moolenaarc5e6a712020-12-04 19:12:14 +0100883However, this #{} syntax is unlike any existing language. As it turns out
884that using a literal key is much more common than using an expression, and
Bram Moolenaar2bede172020-11-19 18:53:18 +0100885considering that JavaScript uses this syntax, using the {} form for dictionary
Bram Moolenaarc5e6a712020-12-04 19:12:14 +0100886literals is considered a much more useful syntax. In Vim9 script the {} form
Bram Moolenaar2bede172020-11-19 18:53:18 +0100887uses literal keys: >
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100888 var dict = {key: value}
Bram Moolenaar2bede172020-11-19 18:53:18 +0100889
Bram Moolenaarc5e6a712020-12-04 19:12:14 +0100890This works for alphanumeric characters, underscore and dash. If you want to
891use another character, use a single or double quoted string: >
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100892 var dict = {'key with space': value}
893 var dict = {"key\twith\ttabs": value}
Bram Moolenaar938ae282023-02-20 20:44:55 +0000894 var dict = {'': value} # empty key
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000895< *E1139*
Bram Moolenaarc5e6a712020-12-04 19:12:14 +0100896In case the key needs to be an expression, square brackets can be used, just
897like in JavaScript: >
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100898 var dict = {["key" .. nr]: value}
Bram Moolenaar2bede172020-11-19 18:53:18 +0100899
Bram Moolenaar2e5910b2021-02-03 17:41:24 +0100900The key type can be string, number, bool or float. Other types result in an
Bram Moolenaard899e512022-05-07 21:54:03 +0100901error. Without using [] the value is used as a string, keeping leading zeros.
902An expression given with [] is evaluated and then converted to a string.
903Leading zeros will then be dropped: >
904 var dict = {000123: 'without', [000456]: 'with'}
Bram Moolenaar2e5910b2021-02-03 17:41:24 +0100905 echo dict
Bram Moolenaard899e512022-05-07 21:54:03 +0100906 {'456': 'with', '000123': 'without'}
907A float only works inside [] because the dot is not accepted otherwise: >
908 var dict = {[00.013]: 'float'}
909 echo dict
910 {'0.013': 'float'}
Bram Moolenaar2e5910b2021-02-03 17:41:24 +0100911
Bram Moolenaar2bede172020-11-19 18:53:18 +0100912
Bram Moolenaar10b94212021-02-19 21:42:57 +0100913No :xit, :t, :k, :append, :change or :insert ~
Bram Moolenaarf10911e2022-01-29 22:20:48 +0000914 *E1100*
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200915These commands are too easily confused with local variable names.
916Instead of `:x` or `:xit` you can use `:exit`.
917Instead of `:t` you can use `:copy`.
Bram Moolenaar10b94212021-02-19 21:42:57 +0100918Instead of `:k` you can use `:mark`.
Bram Moolenaar560979e2020-02-04 22:53:05 +0100919
920
921Comparators ~
922
923The 'ignorecase' option is not used for comparators that use strings.
Bram Moolenaar944697a2022-02-20 19:48:20 +0000924Thus "=~" works like "=~#".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100925
Bram Moolenaare1f3fd12022-08-15 18:51:32 +0100926"is" and "isnot" (|expr-is| and |expr-isnot|) when used on strings now return
927false. In legacy script they just compare the strings, in |Vim9| script they
928check identity, and strings are copied when used, thus two strings are never
Bram Moolenaar71badf92023-04-22 22:40:14 +0100929the same (this might change someday if strings are not copied but reference
Bram Moolenaare1f3fd12022-08-15 18:51:32 +0100930counted).
931
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100932
Bram Moolenaar4c295022021-05-02 17:19:11 +0200933Abort after error ~
934
935In legacy script, when an error is encountered, Vim continues to execute
936following lines. This can lead to a long sequence of errors and need to type
937CTRL-C to stop it. In Vim9 script execution of commands stops at the first
938error. Example: >
939 vim9script
940 var x = does-not-exist
941 echo 'not executed'
942
943
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100944For loop ~
Bram Moolenaara2baa732022-02-04 16:09:54 +0000945 *E1254*
Bram Moolenaar47003982021-12-05 21:54:04 +0000946The loop variable must not be declared yet: >
Bram Moolenaar6304be62021-11-27 10:57:26 +0000947 var i = 1
948 for i in [1, 2, 3] # Error!
949
Bram Moolenaar47003982021-12-05 21:54:04 +0000950It is possible to use a global variable though: >
951 g:i = 1
952 for g:i in [1, 2, 3]
953 echo g:i
954 endfor
955
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100956Legacy Vim script has some tricks to make a for loop over a list handle
957deleting items at the current or previous item. In Vim9 script it just uses
958the index, if items are deleted then items in the list will be skipped.
959Example legacy script: >
960 let l = [1, 2, 3, 4]
961 for i in l
962 echo i
963 call remove(l, index(l, i))
964 endfor
965Would echo:
966 1
967 2
968 3
969 4
970In compiled Vim9 script you get:
971 1
972 3
973Generally, you should not change the list that is iterated over. Make a copy
974first if needed.
Bram Moolenaar7c6cd442022-10-11 21:54:04 +0100975When looping over a list of lists, the nested lists can be changed. The loop
976variable is "final", it cannot be changed but what its value can be changed.
Bram Moolenaar9fbdbb82022-09-27 17:30:34 +0100977 *E1306*
978The depth of loops, :for and :while loops added together, cannot exceed 10.
Bram Moolenaar98a29d02021-01-18 19:55:44 +0100979
980
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100981Conditions and expressions ~
Bram Moolenaar6f4754b2022-01-23 12:07:04 +0000982 *vim9-boolean*
Bram Moolenaar13106602020-10-04 16:06:05 +0200983Conditions and expressions are mostly working like they do in other languages.
984Some values are different from legacy Vim script:
985 value legacy Vim script Vim9 script ~
986 0 falsy falsy
987 1 truthy truthy
988 99 truthy Error!
989 "0" falsy Error!
990 "99" truthy Error!
991 "text" falsy Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100992
Bram Moolenaar13106602020-10-04 16:06:05 +0200993For the "??" operator and when using "!" then there is no error, every value
994is either falsy or truthy. This is mostly like JavaScript, except that an
995empty list and dict is falsy:
996
997 type truthy when ~
Bram Moolenaar7e6a5152021-01-02 16:39:53 +0100998 bool true, v:true or 1
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100999 number non-zero
1000 float non-zero
1001 string non-empty
1002 blob non-empty
1003 list non-empty (different from JavaScript)
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001004 tuple non-empty (different from JavaScript)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001005 dictionary non-empty (different from JavaScript)
Bram Moolenaard1caa942020-04-10 22:10:56 +02001006 func when there is a function name
Bram Moolenaar7e6a5152021-01-02 16:39:53 +01001007 special true or v:true
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001008 job when not NULL
1009 channel when not NULL
1010 class when not NULL
Bram Moolenaar7e6a5152021-01-02 16:39:53 +01001011 object when not NULL (TODO: when isTrue() returns true)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001012
Bram Moolenaar2bb26582020-10-03 22:52:39 +02001013The boolean operators "||" and "&&" expect the values to be boolean, zero or
1014one: >
1015 1 || false == true
1016 0 || 1 == true
1017 0 || false == false
1018 1 && true == true
1019 0 && 1 == false
1020 8 || 0 Error!
1021 'yes' && 0 Error!
1022 [] || 99 Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001023
Bram Moolenaar2bb26582020-10-03 22:52:39 +02001024When using "!" for inverting, there is no error for using any type and the
Bram Moolenaar13106602020-10-04 16:06:05 +02001025result is a boolean. "!!" can be used to turn any value into boolean: >
Bram Moolenaar82be4842021-01-11 19:40:15 +01001026 !'yes' == false
Bram Moolenaar13106602020-10-04 16:06:05 +02001027 !![] == false
Bram Moolenaar82be4842021-01-11 19:40:15 +01001028 !![1, 2, 3] == true
Bram Moolenaar2bb26582020-10-03 22:52:39 +02001029
1030When using "`.."` for string concatenation arguments of simple types are
Bram Moolenaar13106602020-10-04 16:06:05 +02001031always converted to string: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001032 'hello ' .. 123 == 'hello 123'
Bram Moolenaar7e6a5152021-01-02 16:39:53 +01001033 'hello ' .. v:true == 'hello true'
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001034
Bram Moolenaar5da36052021-12-27 15:39:57 +00001035Simple types are Number, Float, Special and Bool. For other types |string()|
1036should be used.
Bram Moolenaar7db29e42022-12-11 15:53:04 +00001037 *false* *true* *null* *null_blob* *null_channel*
dkearns521fb7e2023-11-11 19:33:43 +11001038 *null_class* *null_dict* *null_function* *null_job*
1039 *null_list* *null_object* *null_partial* *null_string*
1040 *E1034*
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001041In Vim9 script one can use the following predefined values: >
1042 true
1043 false
1044 null
1045 null_blob
1046 null_channel
Yegappan Lakshmanane750f8c2023-08-24 07:07:05 -07001047 null_class
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001048 null_dict
1049 null_function
1050 null_job
1051 null_list
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001052 null_tuple
Yegappan Lakshmanane750f8c2023-08-24 07:07:05 -07001053 null_object
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001054 null_partial
1055 null_string
1056`true` is the same as `v:true`, `false` the same as `v:false`, `null` the same
1057as `v:null`.
1058
Bram Moolenaar76db9e02022-11-09 21:21:04 +00001059While `null` has the type "special", the other "null_" values have the type
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001060indicated by their name. Quite often a null value is handled the same as an
1061empty value, but not always. The values can be useful to clear a script-local
1062variable, since they cannot be deleted with `:unlet`. E.g.: >
1063 var theJob = job_start(...)
1064 # let the job do its work
1065 theJob = null_job
1066
1067The values can also be useful as the default value for an argument: >
1068 def MyFunc(b: blob = null_blob)
erraelcea3dac2023-12-25 01:31:23 -08001069 # Note: compare against null, not null_blob,
1070 # to distinguish the default value from an empty blob.
1071 if b == null
1072 # b argument was not given
1073See |null-compare| for more information about testing against null.
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001074
Bram Moolenaar47c532e2022-03-19 15:18:53 +00001075It is possible to compare `null` with any value, this will not give a type
1076error. However, comparing `null` with a number, float or bool will always
1077result in `false`. This is different from legacy script, where comparing
1078`null` with zero or `false` would return `true`.
Bram Moolenaar10e8ff92023-06-10 21:40:39 +01001079 *vim9-false-true*
Bram Moolenaar8acb9cc2022-03-08 13:18:55 +00001080When converting a boolean to a string `false` and `true` are used, not
1081`v:false` and `v:true` like in legacy script. `v:none` has no `none`
1082replacement, it has no equivalent in other languages.
Bram Moolenaar10e8ff92023-06-10 21:40:39 +01001083 *vim9-string-index*
Bram Moolenaar0289a092021-03-14 18:40:19 +01001084Indexing a string with [idx] or taking a slice with [idx : idx] uses character
1085indexes instead of byte indexes. Composing characters are included.
1086Example: >
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02001087 echo 'bár'[1]
1088In legacy script this results in the character 0xc3 (an illegal byte), in Vim9
1089script this results in the string 'á'.
Bram Moolenaar82be4842021-01-11 19:40:15 +01001090A negative index is counting from the end, "[-1]" is the last character.
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001091To exclude the last character use |slice()|.
Bram Moolenaar38a3bfa2021-03-29 22:14:55 +02001092To count composing characters separately use |strcharpart()|.
Bram Moolenaar82be4842021-01-11 19:40:15 +01001093If the index is out of range then an empty string results.
1094
1095In legacy script "++var" and "--var" would be silently accepted and have no
1096effect. This is an error in Vim9 script.
1097
1098Numbers starting with zero are not considered to be octal, only numbers
1099starting with "0o" are octal: "0o744". |scriptversion-4|
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02001100
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001101
Bram Moolenaare46a4402020-06-30 20:38:27 +02001102What to watch out for ~
1103 *vim9-gotchas*
1104Vim9 was designed to be closer to often used programming languages, but at the
1105same time tries to support the legacy Vim commands. Some compromises had to
1106be made. Here is a summary of what might be unexpected.
1107
1108Ex command ranges need to be prefixed with a colon. >
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001109 -> legacy Vim: shifts the previous line to the right
1110 ->func() Vim9: method call in a continuation line
1111 :-> Vim9: shifts the previous line to the right
Bram Moolenaare46a4402020-06-30 20:38:27 +02001112
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001113 %s/a/b legacy Vim: substitute on all lines
Bram Moolenaare46a4402020-06-30 20:38:27 +02001114 x = alongname
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001115 % another Vim9: modulo operator in a continuation line
1116 :%s/a/b Vim9: substitute on all lines
1117 't legacy Vim: jump to mark t
1118 'text'->func() Vim9: method call
1119 :'t Vim9: jump to mark t
Bram Moolenaare46a4402020-06-30 20:38:27 +02001120
Bram Moolenaare7b1ea02020-08-07 19:54:59 +02001121Some Ex commands can be confused with assignments in Vim9 script: >
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001122 g:name = value # assignment
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001123 :g:pattern:cmd # :global command
Bram Moolenaare7b1ea02020-08-07 19:54:59 +02001124
Bram Moolenaar7b829262021-10-13 15:04:34 +01001125To avoid confusion between a `:global` or `:substitute` command and an
1126expression or assignment, a few separators cannot be used when these commands
1127are abbreviated to a single character: ':', '-' and '.'. >
1128 g:pattern:cmd # invalid command - ERROR
1129 s:pattern:repl # invalid command - ERROR
1130 g-pattern-cmd # invalid command - ERROR
1131 s-pattern-repl # invalid command - ERROR
1132 g.pattern.cmd # invalid command - ERROR
1133 s.pattern.repl # invalid command - ERROR
1134
1135Also, there cannot be a space between the command and the separator: >
1136 g /pattern/cmd # invalid command - ERROR
1137 s /pattern/repl # invalid command - ERROR
1138
Bram Moolenaare46a4402020-06-30 20:38:27 +02001139Functions defined with `:def` compile the whole function. Legacy functions
1140can bail out, and the following lines are not parsed: >
1141 func Maybe()
1142 if !has('feature')
1143 return
1144 endif
1145 use-feature
1146 endfunc
1147Vim9 functions are compiled as a whole: >
1148 def Maybe()
1149 if !has('feature')
1150 return
1151 endif
Bram Moolenaar82be4842021-01-11 19:40:15 +01001152 use-feature # May give a compilation error
Bram Moolenaare46a4402020-06-30 20:38:27 +02001153 enddef
1154For a workaround, split it in two functions: >
1155 func Maybe()
1156 if has('feature')
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001157 call MaybeInner()
Bram Moolenaare46a4402020-06-30 20:38:27 +02001158 endif
1159 endfunc
1160 if has('feature')
1161 def MaybeInner()
1162 use-feature
1163 enddef
1164 endif
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001165Or put the unsupported code inside an `if` with a constant expression that
Bram Moolenaar207f0092020-08-30 17:20:20 +02001166evaluates to false: >
1167 def Maybe()
1168 if has('feature')
1169 use-feature
1170 endif
1171 enddef
Bram Moolenaar6aa57292021-08-14 21:25:52 +02001172The `exists_compiled()` function can also be used for this.
1173 *vim9-user-command*
Bram Moolenaar98a29d02021-01-18 19:55:44 +01001174Another side effect of compiling a function is that the presence of a user
Bram Moolenaar82be4842021-01-11 19:40:15 +01001175command is checked at compile time. If the user command is defined later an
1176error will result. This works: >
1177 command -nargs=1 MyCommand echom <q-args>
1178 def Works()
1179 MyCommand 123
1180 enddef
1181This will give an error for "MyCommand" not being defined: >
1182 def Works()
1183 command -nargs=1 MyCommand echom <q-args>
1184 MyCommand 123
1185 enddef
1186A workaround is to invoke the command indirectly with `:execute`: >
1187 def Works()
1188 command -nargs=1 MyCommand echom <q-args>
1189 execute 'MyCommand 123'
1190 enddef
1191
Bram Moolenaar207f0092020-08-30 17:20:20 +02001192Note that for unrecognized commands there is no check for "|" and a following
1193command. This will give an error for missing `endif`: >
1194 def Maybe()
1195 if has('feature') | use-feature | endif
1196 enddef
Bram Moolenaare46a4402020-06-30 20:38:27 +02001197
Bram Moolenaar4072ba52020-12-23 13:56:35 +01001198Other differences ~
1199
1200Patterns are used like 'magic' is set, unless explicitly overruled.
1201The 'edcompatible' option value is not used.
1202The 'gdefault' option value is not used.
1203
Bram Moolenaar130cbfc2021-04-07 21:07:20 +02001204You may also find this wiki useful. It was written by an early adopter of
Bram Moolenaarc8cdf0f2021-03-13 13:28:13 +01001205Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md
Bram Moolenaar4072ba52020-12-23 13:56:35 +01001206
Bram Moolenaar4d8f4762021-06-27 15:18:56 +02001207 *:++* *:--*
1208The ++ and -- commands have been added. They are very similar to adding or
1209subtracting one: >
1210 ++var
1211 var += 1
1212 --var
1213 var -= 1
1214
1215Using ++var or --var in an expression is not supported yet.
1216
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001217==============================================================================
1218
12193. New style functions *fast-functions*
1220
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001221 *:def* *E1028*
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02001222:def[!] {name}([arguments])[: {return-type}]
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001223 Define a new function by the name {name}. The body of
1224 the function follows in the next lines, until the
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001225 matching `:enddef`. *E1073*
1226 *E1011*
1227 The {name} must be less than 100 bytes long.
1228 *E1003* *E1027* *E1056* *E1059*
1229 The type of value used with `:return` must match
1230 {return-type}. When {return-type} is omitted or is
1231 "void" the function is not expected to return
1232 anything.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001233 *E1077* *E1123*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001234 {arguments} is a sequence of zero or more argument
1235 declarations. There are three forms:
1236 {name}: {type}
1237 {name} = {value}
1238 {name}: {type} = {value}
1239 The first form is a mandatory argument, the caller
1240 must always provide them.
1241 The second and third form are optional arguments.
1242 When the caller omits an argument the {value} is used.
1243
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001244 The function will be compiled into instructions when
Bram Moolenaar2547aa92020-07-26 17:00:44 +02001245 called, or when `:disassemble` or `:defcompile` is
1246 used. Syntax and type errors will be produced at that
1247 time.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001248
Bram Moolenaar2547aa92020-07-26 17:00:44 +02001249 It is possible to nest `:def` inside another `:def` or
1250 `:function` up to about 50 levels deep.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001251 *E1117*
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001252 [!] is used as with `:function`. Note that
1253 script-local functions cannot be deleted or redefined
1254 later in Vim9 script. They can only be removed by
1255 reloading the same script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001256
Bram Moolenaara2baa732022-02-04 16:09:54 +00001257 *:enddef* *E1057* *E1152* *E1173*
Bram Moolenaar2547aa92020-07-26 17:00:44 +02001258:enddef End of a function defined with `:def`. It should be on
1259 a line by its own.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001260
Bram Moolenaar130cbfc2021-04-07 21:07:20 +02001261You may also find this wiki useful. It was written by an early adopter of
Bram Moolenaar0289a092021-03-14 18:40:19 +01001262Vim9 script: https://github.com/lacygoill/wiki/blob/master/vim/vim9.md
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001263
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +01001264If the script the function is defined in is Vim9 script, then script-local
1265variables can be accessed without the "s:" prefix. They must be defined
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001266before the function is compiled. If the script the function is defined in is
1267legacy script, then script-local variables must be accessed with the "s:"
Bram Moolenaar130cbfc2021-04-07 21:07:20 +02001268prefix if they do not exist at the time of compiling.
Bram Moolenaar2ecbe532022-07-29 21:36:21 +01001269 *E1269*
1270Script-local variables in a |Vim9| script must be declared at the script
1271level. They cannot be created in a function, also not in a legacy function.
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +01001272
Bram Moolenaar388a5d42020-05-26 21:20:45 +02001273 *:defc* *:defcompile*
Yegappan Lakshmanan4f32c832024-01-12 17:36:40 +01001274:defc[ompile] Compile functions and classes (|class-compile|)
1275 defined in the current script that were not compiled
1276 yet. This will report any errors found during
1277 compilation.
1278
h_east4d496432024-01-27 19:22:28 +09001279:defc[ompile] MyClass Compile all methods in a class. |class-compile|
Bram Moolenaarf79d9dd2022-05-21 15:39:02 +01001280
1281:defc[ompile] {func}
1282:defc[ompile] debug {func}
1283:defc[ompile] profile {func}
1284 Compile function {func}, if needed. Use "debug" and
1285 "profile" to specify the compilation mode.
1286 This will report any errors found during compilation.
Bram Moolenaardd60c362023-02-27 15:49:53 +00001287 {func} call also be "ClassName.functionName" to
1288 compile a function or method in a class.
1289 {func} call also be "ClassName" to compile all
1290 functions and methods in a class.
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +01001291
Bram Moolenaarebdf3c92020-02-15 21:41:42 +01001292 *:disa* *:disassemble*
1293:disa[ssemble] {func} Show the instructions generated for {func}.
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001294 This is for debugging and testing. *E1061*
Bram Moolenaarcc390ff2020-02-29 22:06:30 +01001295 Note that for command line completion of {func} you
1296 can prepend "s:" to find script-local functions.
Bram Moolenaarebdf3c92020-02-15 21:41:42 +01001297
Bram Moolenaar2346a632021-06-13 19:02:49 +02001298:disa[ssemble] profile {func}
1299 Like `:disassemble` but with the instructions used for
Bram Moolenaare0e39172021-01-25 21:14:57 +01001300 profiling.
1301
Bram Moolenaar2346a632021-06-13 19:02:49 +02001302:disa[ssemble] debug {func}
1303 Like `:disassemble` but with the instructions used for
1304 debugging.
1305
Bram Moolenaar7ff78462020-07-10 22:00:53 +02001306Limitations ~
1307
1308Local variables will not be visible to string evaluation. For example: >
Bram Moolenaar2b327002020-12-26 15:39:31 +01001309 def MapList(): list<string>
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001310 var list = ['aa', 'bb', 'cc', 'dd']
Bram Moolenaar7ff78462020-07-10 22:00:53 +02001311 return range(1, 2)->map('list[v:val]')
1312 enddef
1313
1314The map argument is a string expression, which is evaluated without the
1315function scope. Instead, use a lambda: >
Bram Moolenaar2b327002020-12-26 15:39:31 +01001316 def MapList(): list<string>
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001317 var list = ['aa', 'bb', 'cc', 'dd']
Bram Moolenaar22863042021-10-16 15:23:36 +01001318 return range(1, 2)->map((_, v) => list[v])
Bram Moolenaar7ff78462020-07-10 22:00:53 +02001319 enddef
1320
Bram Moolenaar3d2e0312021-12-01 09:27:20 +00001321For commands that are not compiled, such as `:edit`, backtick expansion can be
1322used and it can use the local scope. Example: >
Bram Moolenaar2b327002020-12-26 15:39:31 +01001323 def Replace()
Bram Moolenaar3d2e0312021-12-01 09:27:20 +00001324 var fname = 'blah.txt'
1325 edit `=fname`
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001326 enddef
1327
Bram Moolenaardad44732021-03-31 20:07:33 +02001328Closures defined in a loop will share the same context. For example: >
1329 var flist: list<func>
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001330 for i in range(5)
Bram Moolenaardad44732021-03-31 20:07:33 +02001331 var inloop = i
1332 flist[i] = () => inloop
1333 endfor
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001334 echo range(5)->map((i, _) => flist[i]())
1335 # Result: [4, 4, 4, 4, 4]
Bram Moolenaar47c532e2022-03-19 15:18:53 +00001336< *E1271*
1337A closure must be compiled in the context that it is defined in, so that
1338variables in that context can be found. This mostly happens correctly, except
Bram Moolenaarbe4e0162023-02-02 13:59:48 +00001339when a function is marked for debugging with `:breakadd` after it was compiled.
Bram Moolenaar46eea442022-03-30 10:51:39 +01001340Make sure to define the breakpoint before compiling the outer function.
Bram Moolenaardad44732021-03-31 20:07:33 +02001341
1342The "inloop" variable will exist only once, all closures put in the list refer
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001343to the same instance, which in the end will have the value 4. This is
1344efficient, also when looping many times. If you do want a separate context
Bram Moolenaar71b6d332022-09-10 13:13:14 +01001345for each closure, call a function to define it: >
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001346 def GetClosure(i: number): func
1347 var infunc = i
1348 return () => infunc
Bram Moolenaardad44732021-03-31 20:07:33 +02001349 enddef
1350
1351 var flist: list<func>
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001352 for i in range(5)
1353 flist[i] = GetClosure(i)
Bram Moolenaardad44732021-03-31 20:07:33 +02001354 endfor
Bram Moolenaar53f7fcc2021-07-28 20:10:16 +02001355 echo range(5)->map((i, _) => flist[i]())
1356 # Result: [0, 1, 2, 3, 4]
Bram Moolenaardad44732021-03-31 20:07:33 +02001357
Bram Moolenaara2baa732022-02-04 16:09:54 +00001358In some situations, especially when calling a Vim9 closure from legacy
1359context, the evaluation will fail. *E1248*
1360
Bram Moolenaar71b6d332022-09-10 13:13:14 +01001361Note that at the script level the loop variable will be invalid after the
1362loop, also when used in a closure that is called later, e.g. with a timer.
1363This will generate error |E1302|: >
1364 for n in range(4)
1365 timer_start(500 * n, (_) => {
1366 echowin n
1367 })
1368 endfor
1369
Bram Moolenaar9712ff12022-09-18 13:04:22 +01001370You need to use a block and define a variable there, and use that one in the
1371closure: >
Bram Moolenaar71b6d332022-09-10 13:13:14 +01001372 for n in range(4)
Bram Moolenaar9712ff12022-09-18 13:04:22 +01001373 {
1374 var nr = n
1375 timer_start(500 * n, (_) => {
1376 echowin nr
1377 })
1378 }
Bram Moolenaar71b6d332022-09-10 13:13:14 +01001379 endfor
1380
Bram Moolenaarbe4e0162023-02-02 13:59:48 +00001381Using `:echowindow` is useful in a timer, the messages go into a popup and will
Bram Moolenaar71b6d332022-09-10 13:13:14 +01001382not interfere with what the user is doing when it triggers.
1383
Bram Moolenaara2baa732022-02-04 16:09:54 +00001384
1385Converting a function from legacy to Vim9 ~
1386 *convert_legacy_function_to_vim9*
1387These are the most changes that need to be made to convert a legacy function
1388to a Vim9 function:
1389
1390- Change `func` or `function` to `def`.
1391- Change `endfunc` or `endfunction` to `enddef`.
1392- Add types to the function arguments.
1393- If the function returns something, add the return type.
1394- Change comments to start with # instead of ".
1395
1396 For example, a legacy function: >
1397 func MyFunc(text)
1398 " function body
1399 endfunc
1400< Becomes: >
1401 def MyFunc(text: string): number
1402 # function body
1403 enddef
1404
1405- Remove "a:" used for arguments. E.g.: >
1406 return len(a:text)
1407< Becomes: >
1408 return len(text)
1409
1410- Change `let` used to declare a variable to `var`.
1411- Remove `let` used to assign a value to a variable. This is for local
1412 variables already declared and b: w: g: and t: variables.
1413
1414 For example, legacy function: >
1415 let lnum = 1
1416 let lnum += 3
1417 let b:result = 42
1418< Becomes: >
1419 var lnum = 1
1420 lnum += 3
1421 b:result = 42
1422
1423- Insert white space in expressions where needed.
1424- Change "." used for concatenation to "..".
1425
1426 For example, legacy function: >
1427 echo line(1).line(2)
1428< Becomes: >
1429 echo line(1) .. line(2)
1430
1431- line continuation does not always require a backslash: >
Bram Moolenaar938ae282023-02-20 20:44:55 +00001432 echo ['one',
Bram Moolenaara2baa732022-02-04 16:09:54 +00001433 \ 'two',
1434 \ 'three'
1435 \ ]
1436< Becomes: >
1437 echo ['one',
1438 'two',
1439 'three'
1440 ]
1441
Bram Moolenaar87b4e5c2022-10-01 15:32:46 +01001442
1443Calling a function in an expr option ~
1444 *expr-option-function*
Bram Moolenaarf269eab2022-10-03 18:04:35 +01001445The value of a few options, such as 'foldexpr', is an expression that is
1446evaluated to get a value. The evaluation can have quite a bit of overhead.
1447One way to minimize the overhead, and also to keep the option value very
1448simple, is to define a compiled function and set the option to call it
1449without arguments. Example: >
Bram Moolenaar87b4e5c2022-10-01 15:32:46 +01001450 vim9script
1451 def MyFoldFunc(): any
1452 ... compute fold level for line v:lnum
1453 return level
1454 enddef
1455 set foldexpr=s:MyFoldFunc()
1456
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001457==============================================================================
1458
14594. Types *vim9-types*
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001460 *E1008* *E1009* *E1010* *E1012*
1461 *E1013* *E1029* *E1030*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001462The following builtin types are supported:
1463 bool
1464 number
1465 float
1466 string
1467 blob
Bram Moolenaard77a8522020-04-03 21:59:57 +02001468 list<{type}>
1469 dict<{type}>
Yegappan Lakshmanan6fa62082025-04-03 21:26:34 +02001470 object<{type}>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001471 job
1472 channel
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001473 tuple<{type}>
1474 tuple<{type}, {type}, ...>
1475 tuple<...list<{type}>>
1476 tuple<{type}, ...list<{type}>>
Bram Moolenaarb17893a2020-03-14 08:19:51 +01001477 func
Bram Moolenaard1caa942020-04-10 22:10:56 +02001478 func: {type}
Bram Moolenaard77a8522020-04-03 21:59:57 +02001479 func({type}, ...)
1480 func({type}, ...): {type}
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001481 void
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001482
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001483These types can be used in declarations, but no simple value will actually
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001484have the "void" type. Trying to use a void (e.g. a function without a
Bram Moolenaara2baa732022-02-04 16:09:54 +00001485return value) results in error *E1031* *E1186* .
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001486
Bram Moolenaard77a8522020-04-03 21:59:57 +02001487There is no array type, use list<{type}> instead. For a list constant an
Bram Moolenaar71badf92023-04-22 22:40:14 +01001488efficient implementation is used that avoids allocating a lot of small pieces
1489of memory.
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001490 *tuple-type*
1491A tuple type can be declared in more or less specific ways:
1492tuple<number> a tuple with a single item of type |Number|
1493tuple<number, string> a tuple with two items of type |Number| and
1494 |String|
1495tuple<number, float, bool> a tuple with three items of type |Number|,
Hirohito Higashi0ed11ba2025-04-18 18:45:31 +02001496 |Float| and |Boolean|
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001497tuple<...list<number>> a variadic tuple with zero or more items of
Hirohito Higashi0ed11ba2025-04-18 18:45:31 +02001498 type |Number|
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001499tuple<number, ...list<string>> a tuple with an item of type |Number| followed
Hirohito Higashi0ed11ba2025-04-18 18:45:31 +02001500 by zero or more items of type |String|
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001501
1502Examples: >
1503 var myTuple: tuple<number> = (20,)
1504 var myTuple: tuple<number, string> = (30, 'vim')
1505 var myTuple: tuple<number, float, bool> = (40, 1.1, true)
1506 var myTuple: tuple<...list<string>> = ('a', 'b', 'c')
1507 var myTuple: tuple<number, ...list<string>> = (3, 'a', 'b', 'c')
1508<
1509 *variadic-tuple* *E1539*
1510A variadic tuple has zero or more items of the same type. The type of a
1511variadic tuple must end with a list type. Examples: >
1512 var myTuple: tuple<...list<number>> = (1, 2, 3)
1513 var myTuple: tuple<...list<string>> = ('a', 'b', 'c')
1514 var myTuple: tuple<...list<bool>> = ()
1515<
Ernie Rael3ec6c1f2023-10-21 11:45:38 +02001516 *vim9-func-declaration* *E1005* *E1007*
Bram Moolenaard77a8522020-04-03 21:59:57 +02001517A partial and function can be declared in more or less specific ways:
1518func any kind of function reference, no type
Bram Moolenaard1caa942020-04-10 22:10:56 +02001519 checking for arguments or return value
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001520func: void any number and type of arguments, no return
1521 value
Bram Moolenaard77a8522020-04-03 21:59:57 +02001522func: {type} any number and type of arguments with specific
1523 return type
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001524
1525func() function with no argument, does not return a
1526 value
1527func(): void same
1528func(): {type} function with no argument and return type
1529
Bram Moolenaard1caa942020-04-10 22:10:56 +02001530func({type}) function with argument type, does not return
Bram Moolenaard77a8522020-04-03 21:59:57 +02001531 a value
Bram Moolenaard1caa942020-04-10 22:10:56 +02001532func({type}): {type} function with argument type and return type
1533func(?{type}) function with type of optional argument, does
1534 not return a value
Ernie Raela5a15342023-10-23 19:08:38 +02001535func(...list<{type}>) function with type of list for variable number
1536 of arguments, does not return a value
1537func({type}, ?{type}, ...list<{type}>): {type}
Bram Moolenaard1caa942020-04-10 22:10:56 +02001538 function with:
1539 - type of mandatory argument
1540 - type of optional argument
Ernie Raela5a15342023-10-23 19:08:38 +02001541 - type of list for variable number of
1542 arguments
Bram Moolenaard1caa942020-04-10 22:10:56 +02001543 - return type
Bram Moolenaard77a8522020-04-03 21:59:57 +02001544
1545If the return type is "void" the function does not return a value.
1546
1547The reference can also be a |Partial|, in which case it stores extra arguments
1548and/or a dictionary, which are not visible to the caller. Since they are
1549called in the same way the declaration is the same.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001550
1551Custom types can be defined with `:type`: >
1552 :type MyList list<string>
Bram Moolenaar127542b2020-08-09 17:22:04 +02001553Custom types must start with a capital letter, to avoid name clashes with
1554builtin types added later, similarly to user functions.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001555
1556And classes and interfaces can be used as types: >
1557 :class MyClass
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001558 :var mine: MyClass
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001559
1560 :interface MyInterface
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001561 :var mine: MyInterface
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001562
1563 :class MyTemplate<Targ>
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001564 :var mine: MyTemplate<number>
1565 :var mine: MyTemplate<string>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001566
1567 :class MyInterface<Targ>
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001568 :var mine: MyInterface<number>
1569 :var mine: MyInterface<string>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001570{not implemented yet}
1571
1572
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001573Variable types and type casting ~
1574 *variable-types*
Bram Moolenaar64d662d2020-08-09 19:02:50 +02001575Variables declared in Vim9 script or in a `:def` function have a type, either
1576specified explicitly or inferred from the initialization.
1577
1578Global, buffer, window and tab page variables do not have a specific type, the
1579value can be changed at any time, possibly changing the type. Therefore, in
1580compiled code the "any" type is assumed.
1581
1582This can be a problem when the "any" type is undesired and the actual type is
1583expected to always be the same. For example, when declaring a list: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001584 var l: list<number> = [1, g:two]
Bram Moolenaar4072ba52020-12-23 13:56:35 +01001585At compile time Vim doesn't know the type of "g:two" and the expression type
1586becomes list<any>. An instruction is generated to check the list type before
1587doing the assignment, which is a bit inefficient.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001588 *type-casting* *E1104*
Bram Moolenaar4072ba52020-12-23 13:56:35 +01001589To avoid this, use a type cast: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001590 var l: list<number> = [1, <number>g:two]
Bram Moolenaar4072ba52020-12-23 13:56:35 +01001591The compiled code will then only check that "g:two" is a number and give an
1592error if it isn't. This is called type casting.
Bram Moolenaar64d662d2020-08-09 19:02:50 +02001593
1594The syntax of a type cast is: "<" {type} ">". There cannot be white space
1595after the "<" or before the ">" (to avoid them being confused with
1596smaller-than and bigger-than operators).
1597
1598The semantics is that, if needed, a runtime type check is performed. The
1599value is not actually changed. If you need to change the type, e.g. to change
1600it to a string, use the |string()| function. Or use |str2nr()| to convert a
1601string to a number.
1602
Bram Moolenaar2ecbe532022-07-29 21:36:21 +01001603If a type is given where it is not expected you can get *E1272* .
1604
h_eastba77bbb2023-10-03 04:47:13 +09001605If a type is incomplete you get *E1363* , e.g. when you have an object for
Bram Moolenaar71badf92023-04-22 22:40:14 +01001606which the class is not known (usually that is a null object).
Bram Moolenaar64d662d2020-08-09 19:02:50 +02001607
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001608Type inference ~
1609 *type-inference*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001610In general: Whenever the type is clear it can be omitted. For example, when
1611declaring a variable and giving it a value: >
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001612 var name = 0 # infers number type
1613 var name = 'hello' # infers string type
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001614
Bram Moolenaar127542b2020-08-09 17:22:04 +02001615The type of a list and dictionary comes from the common type of the values.
1616If the values all have the same type, that type is used for the list or
1617dictionary. If there is a mix of types, the "any" type is used. >
1618 [1, 2, 3] list<number>
1619 ['a', 'b', 'c'] list<string>
1620 [1, 'x', 3] list<any>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001621
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001622The common type of function references, if they do not all have the same
1623number of arguments, uses "(...)" to indicate the number of arguments is not
1624specified. For example: >
1625 def Foo(x: bool)
1626 enddef
1627 def Bar(x: bool, y: bool)
1628 enddef
1629 var funclist = [Foo, Bar]
1630 echo funclist->typename()
1631Results in:
1632 list<func(...)>
1633
Bram Moolenaar130cbfc2021-04-07 21:07:20 +02001634For script-local variables in Vim9 script the type is checked, also when the
1635variable was declared in a legacy function.
1636
Bram Moolenaar9da17d72022-02-09 21:50:44 +00001637When a type has been declared this is attached to a List or Dictionary. When
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001638later some expression attempts to change the type an error will be given: >
1639 var ll: list<number> = [1, 2, 3]
Bram Moolenaarc4573eb2022-01-31 15:40:56 +00001640 ll->extend(['x']) # Error, 'x' is not a number
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001641
Bram Moolenaar9da17d72022-02-09 21:50:44 +00001642If the type is not declared then it is allowed to change: >
Bram Moolenaarc4573eb2022-01-31 15:40:56 +00001643 [1, 2, 3]->extend(['x']) # result: [1, 2, 3, 'x']
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001644
Bram Moolenaar9da17d72022-02-09 21:50:44 +00001645For a variable declaration an inferred type matters: >
1646 var ll = [1, 2, 3]
1647 ll->extend(['x']) # Error, 'x' is not a number
1648That is because the declaration looks like a list of numbers, thus is
1649equivalent to: >
1650 var ll: list<number> = [1, 2, 3]
1651If you do want a more permissive list you need to declare the type: >
Bram Moolenaarbe4e0162023-02-02 13:59:48 +00001652 var ll: list<any> = [1, 2, 3]
Bram Moolenaar9da17d72022-02-09 21:50:44 +00001653 ll->extend(['x']) # OK
1654
Bram Moolenaar207f0092020-08-30 17:20:20 +02001655
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001656Stricter type checking ~
1657 *type-checking*
Bram Moolenaar207f0092020-08-30 17:20:20 +02001658In legacy Vim script, where a number was expected, a string would be
1659automatically converted to a number. This was convenient for an actual number
Bram Moolenaar130cbfc2021-04-07 21:07:20 +02001660such as "123", but leads to unexpected problems (and no error message) if the
Bram Moolenaar207f0092020-08-30 17:20:20 +02001661string doesn't start with a number. Quite often this leads to hard-to-find
Bram Moolenaar944697a2022-02-20 19:48:20 +00001662bugs. e.g.: >
1663 echo 123 == '123'
1664< 1 ~
1665With an accidental space: >
1666 echo 123 == ' 123'
1667< 0 ~
Bram Moolenaara2baa732022-02-04 16:09:54 +00001668 *E1206* *E1210* *E1212*
Bram Moolenaar207f0092020-08-30 17:20:20 +02001669In Vim9 script this has been made stricter. In most places it works just as
Bram Moolenaar944697a2022-02-20 19:48:20 +00001670before if the value used matches the expected type. There will sometimes be
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001671an error, thus breaking backwards compatibility. For example:
Bram Moolenaar207f0092020-08-30 17:20:20 +02001672- Using a number other than 0 or 1 where a boolean is expected. *E1023*
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001673- Using a string value when setting a number option.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001674- Using a number where a string is expected. *E1024* *E1105*
Bram Moolenaar207f0092020-08-30 17:20:20 +02001675
Bram Moolenaar22863042021-10-16 15:23:36 +01001676One consequence is that the item type of a list or dict given to |map()| must
Bram Moolenaar944697a2022-02-20 19:48:20 +00001677not change, if the type was declared. This will give an error in Vim9
1678script: >
1679 var mylist: list<number> = [1, 2, 3]
1680 echo map(mylist, (i, v) => 'item ' .. i)
1681< E1012: Type mismatch; expected number but got string in map() ~
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001682
Bram Moolenaar944697a2022-02-20 19:48:20 +00001683Instead use |mapnew()|, it creates a new list: >
1684 var mylist: list<number> = [1, 2, 3]
1685 echo mapnew(mylist, (i, v) => 'item ' .. i)
1686< ['item 0', 'item 1', 'item 2'] ~
1687
1688If the item type was not declared or determined to be "any" it can change to a
1689more specific type. E.g. when a list of mixed types gets changed to a list of
1690strings: >
Bram Moolenaar90df4b92021-07-07 20:26:08 +02001691 var mylist = [1, 2.0, '3']
1692 # typename(mylist) == "list<any>"
1693 map(mylist, (i, v) => 'item ' .. i)
1694 # typename(mylist) == "list<string>", no error
Bram Moolenaar944697a2022-02-20 19:48:20 +00001695
1696There is a subtle difference between using a list constant directly and
Bram Moolenaarafa048f2022-02-22 20:43:36 +00001697through a variable declaration. Because of type inference, when using a list
Bram Moolenaar944697a2022-02-20 19:48:20 +00001698constant to initialize a variable, this also sets the declared type: >
1699 var mylist = [1, 2, 3]
1700 # typename(mylist) == "list<number>"
1701 echo map(mylist, (i, v) => 'item ' .. i) # Error!
1702
1703When using the list constant directly, the type is not declared and is allowed
1704to change: >
1705 echo map([1, 2, 3], (i, v) => 'item ' .. i) # OK
1706
1707The reasoning behind this is that when a type is declared and the list is
1708passed around and changed, the declaration must always hold. So that you can
1709rely on the type to match the declared type. For a constant this is not
1710needed.
1711
1712 *E1158*
Bram Moolenaar9faec4e2021-02-27 16:38:07 +01001713Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use
Bram Moolenaar944697a2022-02-20 19:48:20 +00001714|flattennew()| instead. Since |flatten()| is intended to always change the
1715type, it can not be used in Vim9 script.
1716
Ernie Rael3ec6c1f2023-10-21 11:45:38 +02001717Assigning to a funcref with specified arguments (see |vim9-func-declaration|)
1718does strict type checking of the arguments. For variable number of arguments
1719the type must match: >
1720 var FuncRef: func(string, number, bool): number
1721 FuncRef = (v1: string, v2: number, v3: bool) => 777 # OK
1722 FuncRef = (v1: string, v2: number, v3: number) => 777 # Error!
1723 # variable number of arguments must have same type
1724 var FuncVA: func(...list<string>): number
1725 FuncVA = (...v: list<number>): number => v # Error!
1726 FuncVA = (...v: list<any>): number => v # OK, `any` runtime check
1727 FuncVA = (v1: string, v: string2): number => 333 # Error!
1728 FuncVA = (v: list<string>): number => 3 # Error!
1729
zeertzjq61e984e2023-12-09 15:18:33 +08001730If the destination funcref has no specified arguments, then there is no
Ernie Rael3ec6c1f2023-10-21 11:45:38 +02001731argument type checking: >
1732 var FuncUnknownArgs: func: number
1733 FuncUnknownArgs = (v): number => v # OK
1734 FuncUnknownArgs = (v1: string, v2: string): number => 3 # OK
Ernie Raela5a15342023-10-23 19:08:38 +02001735 FuncUnknownArgs = (...v1: list<string>): number => 333 # OK
1736<
Bram Moolenaara2baa732022-02-04 16:09:54 +00001737 *E1211* *E1217* *E1218* *E1219* *E1220* *E1221*
1738 *E1222* *E1223* *E1224* *E1225* *E1226* *E1227*
Dominique Pellee764d1b2023-03-12 21:20:59 +00001739 *E1228* *E1238* *E1250* *E1251* *E1252* *E1256*
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001740 *E1297* *E1298* *E1301* *E1528* *E1529* *E1530*
1741 *E1531* *E1534*
Bram Moolenaara2baa732022-02-04 16:09:54 +00001742Types are checked for most builtin functions to make it easier to spot
1743mistakes.
Bram Moolenaar82be4842021-01-11 19:40:15 +01001744
erraelcea3dac2023-12-25 01:31:23 -08001745Categories of variables, defaults and null handling ~
1746 *variable-categories* *null-variables*
1747There are categories of variables:
1748 primitive number, float, boolean
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001749 container string, blob, list, tuple, dict
erraelcea3dac2023-12-25 01:31:23 -08001750 specialized function, job, channel, user-defined-object
1751
1752When declaring a variable without an initializer, an explicit type must be
1753provided. Each category has different default initialization semantics. Here's
1754an example for each category: >
1755 var num: number # primitives default to a 0 equivalent
1756 var cont: list<string> # containers default to an empty container
1757 var spec: job # specialized variables default to null
1758<
1759Vim does not have a familiar null value; it has various null_<type> predefined
1760values, for example |null_string|, |null_list|, |null_job|. Primitives do not
1761have a null_<type>. The typical use cases for null_<type> are:
h_east4d496432024-01-27 19:22:28 +09001762- to clear a variable and release its resources;
1763- as a default for a parameter in a function definition, see |null-compare|.
erraelcea3dac2023-12-25 01:31:23 -08001764
1765For a specialized variable, like `job`, null_<type> is used to clear the
1766resources. For a container variable, resources can also be cleared by
1767assigning an empty container to the variable. For example: >
1768 var j: job = job_start(...)
1769 # ... job does its work
1770 j = null_job # clear the variable and release the job's resources
1771
1772 var l: list<any>
1773 # ... add lots of stuff to list
1774 l = [] # clear the variable and release container resources
1775Using the empty container, rather than null_<type>, to clear a container
1776variable may avoid null complications as described in |null-anomalies|.
1777
1778The initialization semantics of container variables and specialized variables
1779differ. An uninitialized container defaults to an empty container: >
1780 var l1: list<string> # empty container
1781 var l2: list<string> = [] # empty container
1782 var l3: list<string> = null_list # null container
1783"l1" and "l2" are equivalent and indistinguishable initializations; but "l3"
1784is a null container. A null container is similar to, but different from, an
1785empty container, see |null-anomalies|.
1786
1787Specialized variables default to null. These job initializations are
1788equivalent and indistinguishable: >
1789 var j1: job
1790 var j2: job = null_job
1791 var j3 = null_job
1792
1793When a list or dict is declared, if the item type is not specified and can not
1794be inferred, then the type is "any": >
1795 var d1 = {} # type is "dict<any>"
1796 var d2 = null_dict # type is "dict<any>"
1797
1798Declaring a function, see |vim9-func-declaration|, is particularly unique.
1799
1800 *null-compare*
1801For familiar null compare semantics, where a null container is not equal to
1802an empty container, do not use null_<type> in a comparison: >
1803 vim9script
1804 def F(arg: list<string> = null_list)
1805 if arg == null
1806 echo "null"
1807 else
1808 echo printf("not null, %sempty", empty(arg) ? '' : 'not ')
1809 endif
1810 enddef
1811 F() # output: "null"
1812 F(null_list) # output: "null"
1813 F([]) # output: "not null, empty"
1814 F(['']) # output: "not null, not empty"
h_east4d496432024-01-27 19:22:28 +09001815The above function takes a list of strings and reports on it.
erraelcea3dac2023-12-25 01:31:23 -08001816Change the above function signature to accept different types of arguments: >
1817 def F(arg: list<any> = null_list) # any type of list
1818 def F(arg: any = null) # any type
1819<
1820In the above example, where the goal is to distinguish a null list from an
1821empty list, comparing against `null` instead of `null_list` is the correct
1822choice. The basic reason is because "null_list == null" and "[] != null".
1823Comparing to `null_list` fails since "[] == null_list". In the following section
1824there are details about comparison results.
1825
1826 *null-details* *null-anomalies*
1827This section describes issues about using null and null_<type>; included below
1828are the enumerated results of null comparisons. In some cases, if familiar
1829with vim9 null semantics, the programmer may chose to use null_<type> in
1830comparisons and/or other situations.
1831
1832Elsewhere in the documentation it says:
h_east4d496432024-01-27 19:22:28 +09001833 Quite often a null value is handled the same as an empty value, but
1834 not always
erraelcea3dac2023-12-25 01:31:23 -08001835Here's an example: >
1836 vim9script
1837 var s1: list<string>
1838 var s2: list<string> = null_list
1839 echo s1 # output: "[]"
1840 echo s2 # output: "[]"
h_east4d496432024-01-27 19:22:28 +09001841
erraelcea3dac2023-12-25 01:31:23 -08001842 echo s1 + ['a'] # output: "['a']"
1843 echo s2 + ['a'] # output: "['a']"
h_east4d496432024-01-27 19:22:28 +09001844
erraelcea3dac2023-12-25 01:31:23 -08001845 echo s1->add('a') # output: "['a']"
1846 echo s2->add('a') # E1130: Can not add to null list
1847<
1848Two values equal to a null_<type> are not necessarily equal to each other: >
1849 vim9script
1850 echo {} == null_dict # true
1851 echo null_dict == null # true
1852 echo {} == null # false
1853<
1854Unlike the other containers, an uninitialized string is equal to null. The
1855'is' operator can be used to determine if it is a null_string: >
1856 vim9script
1857 var s1: string
1858 var s2 = null_string
1859 echo s1 == null # true - this is unexpected
1860 echo s2 == null # true
1861 echo s2 is null_string # true
1862
1863 var b1: blob
1864 var b2 = null_blob
1865 echo b1 == null # false
1866 echo b2 == null # true
1867<
1868Any variable initialized to the null_<type> is equal to the null_<type> and is
1869also equal to null. For example: >
1870 vim9script
1871 var x = null_blob
1872 echo x == null_blob # true
1873 echo x == null # true
1874<
1875An uninitialized variable is usually equal to null; it depends on its type:
1876 var s: string s == null
1877 var b: blob b != null ***
1878 var l: list<any> l != null ***
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001879 var t: tuple<any> t != null ***
erraelcea3dac2023-12-25 01:31:23 -08001880 var d: dict<any> d != null ***
1881 var f: func f == null
1882 var j: job j == null
1883 var c: channel c == null
1884 var o: Class o == null
1885
1886A variable initialized to empty equals null_<type>; but not null:
1887 var s2: string = "" == null_string != null
1888 var b2: blob = 0z == null_blob != null
1889 var l2: list<any> = [] == null_list != null
Yegappan Lakshmanan9cb865e2025-03-23 16:42:16 +01001890 var t2: tuple<any> = () == null_tuple != null
erraelcea3dac2023-12-25 01:31:23 -08001891 var d2: dict<any> = {} == null_dict != null
1892
1893NOTE: the specialized variables, like job, default to null value and have no
1894corresponding empty value.
1895
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001896==============================================================================
1897
Bram Moolenaar30fd8202020-09-26 15:09:30 +020018985. Namespace, Import and Export
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001899 *vim9script* *vim9-export* *vim9-import*
1900
Bram Moolenaarfd31be22022-01-16 14:46:06 +00001901A Vim9 script can be written to be imported. This means that some items are
1902intentionally exported, made available to other scripts. When the exporting
1903script is imported in another script, these exported items can then be used in
1904that script. All the other items remain script-local in the exporting script
1905and cannot be accessed by the importing script.
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00001906
1907This mechanism exists for writing a script that can be sourced (imported) by
1908other scripts, while making sure these other scripts only have access to what
1909you want them to. This also avoids using the global namespace, which has a
Bram Moolenaar6ba83ba2022-06-12 22:15:57 +01001910risk of name collisions. For example when you have two plugins with similar
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00001911functionality.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001912
Bram Moolenaarfd31be22022-01-16 14:46:06 +00001913You can cheat by using the global namespace explicitly. That should be done
1914only for things that really are global.
Bram Moolenaar207f0092020-08-30 17:20:20 +02001915
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001916
1917Namespace ~
Bram Moolenaardcc58e02020-12-28 20:53:21 +01001918 *vim9-namespace*
Bram Moolenaar560979e2020-02-04 22:53:05 +01001919To recognize a file that can be imported the `vim9script` statement must
Bram Moolenaard3f8a9e2021-02-17 21:57:03 +01001920appear as the first statement in the file (see |vim9-mix| for an exception).
1921It tells Vim to interpret the script in its own namespace, instead of the
1922global namespace. If a file starts with: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001923 vim9script
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001924 var myvar = 'yes'
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001925Then "myvar" will only exist in this file. While without `vim9script` it would
1926be available as `g:myvar` from any other script and function.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00001927 *E1101*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001928The variables at the file level are very much like the script-local "s:"
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +02001929variables in legacy Vim script, but the "s:" is omitted. And they cannot be
1930deleted.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001931
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +02001932In Vim9 script the global "g:" namespace can still be used as before. And the
1933"w:", "b:" and "t:" namespaces. These have in common that variables are not
Bram Moolenaar9712ff12022-09-18 13:04:22 +01001934declared, have no specific type and they can be deleted. *E1304*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001935
1936A side effect of `:vim9script` is that the 'cpoptions' option is set to the
1937Vim default value, like with: >
1938 :set cpo&vim
1939One of the effects is that |line-continuation| is always enabled.
Bram Moolenaar3e191692021-03-17 17:46:00 +01001940The original value of 'cpoptions' is restored at the end of the script, while
1941flags added or removed in the script are also added to or removed from the
1942original value to get the same effect. The order of flags may change.
Bram Moolenaar71eb3ad2021-12-26 12:07:30 +00001943In the |vimrc| file sourced on startup this does not happen.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001944
Bram Moolenaard3f8a9e2021-02-17 21:57:03 +01001945 *vim9-mix*
1946There is one way to use both legacy and Vim9 syntax in one script file: >
1947 " comments may go here
1948 if !has('vim9script')
1949 " legacy script commands go here
1950 finish
1951 endif
1952 vim9script
1953 # Vim9 script commands go here
1954This allows for writing a script that takes advantage of the Vim9 script
Bram Moolenaar9faec4e2021-02-27 16:38:07 +01001955syntax if possible, but will also work on a Vim version without it.
Bram Moolenaard3f8a9e2021-02-17 21:57:03 +01001956
Konfektde4b2442025-03-05 21:03:21 +01001957Note that Vim9 syntax changed before Vim 9 so that scripts using the current
1958syntax (such as "import from" instead of "import") might throw errors.
1959To prevent these, a safer check could be for |v:version| >= 900 instead.
1960
Bram Moolenaard3f8a9e2021-02-17 21:57:03 +01001961This can only work in two ways:
19621. The "if" statement evaluates to false, the commands up to `endif` are
1963 skipped and `vim9script` is then the first command actually executed.
19642. The "if" statement evaluates to true, the commands up to `endif` are
1965 executed and `finish` bails out before reaching `vim9script`.
1966
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001967
1968Export ~
1969 *:export* *:exp*
Bram Moolenaar2547aa92020-07-26 17:00:44 +02001970Exporting an item can be written as: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001971 export const EXPORTED_CONST = 1234
Bram Moolenaar30fd8202020-09-26 15:09:30 +02001972 export var someValue = ...
1973 export final someValue = ...
1974 export const someValue = ...
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001975 export def MyFunc() ...
1976 export class MyClass ...
Bram Moolenaar74235772021-06-12 14:53:05 +02001977 export interface MyClass ...
Yegappan Lakshmanana81cf8b2025-01-19 22:20:34 +01001978 export enum MyEnum ...
Bram Moolenaar6f4754b2022-01-23 12:07:04 +00001979< *E1043* *E1044*
Yegappan Lakshmanana81cf8b2025-01-19 22:20:34 +01001980As this suggests, only constants, variables, `:def` functions, classes,
1981interfaces and enums can be exported.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001982
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001983 *E1042*
1984`:export` can only be used in Vim9 script, at the script level.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001985
1986
1987Import ~
Bram Moolenaar2ecbe532022-07-29 21:36:21 +01001988 *:import* *:imp* *E1094* *E1047* *E1262*
1989 *E1048* *E1049* *E1053* *E1071* *E1088* *E1236*
Bram Moolenaar5ed11532022-07-06 13:18:11 +01001990The exported items can be imported in another script. The import syntax has
1991two forms. The simple form: >
1992 import {filename}
1993<
1994Where {filename} is an expression that must evaluate to a string. In this
1995form the filename should end in ".vim" and the portion before ".vim" will
1996become the script local name of the namespace. For example: >
Bram Moolenaard5f400c2022-01-06 21:10:28 +00001997 import "myscript.vim"
Bram Moolenaar5ed11532022-07-06 13:18:11 +01001998<
1999This makes each exported item in "myscript.vim" available as "myscript.item".
Bram Moolenaara2baa732022-02-04 16:09:54 +00002000 *:import-as* *E1257* *E1261*
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002001In case the name is long or ambiguous, this form can be used to specify
2002another name: >
2003 import {longfilename} as {name}
2004<
2005In this form {name} becomes a specific script local name for the imported
2006namespace. Therefore {name} must consist of letters, digits and '_', like
2007|internal-variables|. The {longfilename} expression must evaluate to any
2008filename. For example: >
2009 import "thatscript.vim.v2" as that
Bram Moolenaara2baa732022-02-04 16:09:54 +00002010< *E1060* *E1258* *E1259* *E1260*
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002011Then you can use "that.item", etc. You are free to choose the name "that".
2012Use something that will be recognized as referring to the imported script.
2013Avoid command names, command modifiers and builtin function names, because the
Aliaksei Budaveib043ff32023-10-03 17:39:53 +03002014name will shadow them. It's better not to start the name with a capital
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002015letter, since it can then also shadow global user commands and functions.
2016Also, you cannot use the name for something else in the script, such as a
2017function or variable name.
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002018
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00002019In case the dot in the name is undesired, a local reference can be made for a
2020function: >
2021 var LongFunc = that.LongFuncName
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002022
2023This also works for constants: >
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00002024 const MAXLEN = that.MAX_LEN_OF_NAME
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002025
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00002026This does not work for variables, since the value would be copied once and
2027when changing the variable the copy will change, not the original variable.
2028You will need to use the full name, with the dot.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002029
Bram Moolenaar4db572e2021-07-18 18:21:38 +02002030`:import` can not be used in a function. Imported items are intended to exist
2031at the script level and only imported once.
2032
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002033The script name after `import` can be:
2034- A relative path, starting "." or "..". This finds a file relative to the
2035 location of the script file itself. This is useful to split up a large
2036 plugin into several files.
2037- An absolute path, starting with "/" on Unix or "D:/" on MS-Windows. This
Bram Moolenaarcb80aa22020-10-26 21:12:46 +01002038 will rarely be used.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002039- A path not being relative or absolute. This will be found in the
2040 "import" subdirectories of 'runtimepath' entries. The name will usually be
2041 longer and unique, to avoid loading the wrong file.
Bram Moolenaar6aa57292021-08-14 21:25:52 +02002042 Note that "after/import" is not used.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002043
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00002044If the name does not end in ".vim" then the use of "as name" is required.
2045
Hirohito Higashifbe4a8f2025-04-27 15:28:30 +02002046Once a Vim9 script file has been imported, the result is cached and used the
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002047next time the same script is imported. It will not be read again.
Bram Moolenaard5f400c2022-01-06 21:10:28 +00002048
2049It is not allowed to import the same script twice, also when using two
2050different "as" names.
Bram Moolenaar2f0936c2022-01-08 21:51:59 +00002051
2052When using the imported name the dot and the item name must be in the same
2053line, there can be no line break: >
2054 echo that.
2055 name # Error!
2056 echo that
2057 .name # Error!
Bram Moolenaar48c3f4e2022-08-08 15:42:38 +01002058< *import-map*
Hirohito Higashifbe4a8f2025-04-27 15:28:30 +02002059When you've imported a function from one script into a Vim9 script you can
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002060refer to the imported function in a mapping by prefixing it with |<SID>|: >
Bram Moolenaar89445512022-04-14 12:58:23 +01002061 noremap <silent> ,a :call <SID>name.Function()<CR>
2062
2063When the mapping is defined "<SID>name." will be replaced with <SNR> and the
2064script ID of the imported script.
Bram Moolenaar6ba83ba2022-06-12 22:15:57 +01002065An even simpler solution is using |<ScriptCmd>|: >
2066 noremap ,a <ScriptCmd>name.Function()<CR>
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002067
2068Note that this does not work for variables, only for functions.
2069
2070 *import-legacy* *legacy-import*
2071`:import` can also be used in legacy Vim script. The imported namespace still
2072becomes script-local, even when the "s:" prefix is not given. For example: >
zeertzjqd086b8f2024-02-25 15:42:52 +08002073 import "myfile.vim"
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002074 call s:myfile.MyFunc()
2075
2076And using the "as name" form: >
2077 import "otherfile.vim9script" as that
2078 call s:that.OtherFunc()
2079
Bram Moolenaar9712ff12022-09-18 13:04:22 +01002080However, the namespace cannot be resolved on its own: >
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002081 import "that.vim"
2082 echo s:that
2083 " ERROR: E1060: Expected dot after name: s:that
2084<
2085This also affects the use of |<SID>| in the legacy mapping context. Since
2086|<SID>| is only a valid prefix for a function and NOT for a namespace, you
h_eastba77bbb2023-10-03 04:47:13 +09002087cannot use it to scope a function in a script local namespace. Instead of
2088prefixing the function with |<SID>| you should use|<ScriptCmd>|. For example:
2089>
Bram Moolenaar5ed11532022-07-06 13:18:11 +01002090 noremap ,a <ScriptCmd>:call s:that.OtherFunc()<CR>
Bram Moolenaar6ba83ba2022-06-12 22:15:57 +01002091<
Christian Brabandtd9a1f262025-01-21 22:17:50 +01002092 *:import-cycle*
2093The `import` commands are executed when encountered. If script A imports
2094script B, and B (directly or indirectly) imports A, this will be skipped over.
2095At this point items in A after "import B" will not have been processed and
2096defined yet. Therefore cyclic imports can exist and not result in an error
2097directly, but may result in an error for items in A after "import B" not being
2098defined. This does not apply to autoload imports, see the next section.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002099
2100
Bram Moolenaarfd31be22022-01-16 14:46:06 +00002101Importing an autoload script ~
Bram Moolenaarfd999452022-08-24 18:30:14 +01002102 *vim9-autoload* *import-autoload*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002103For optimal startup speed, loading scripts should be postponed until they are
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002104actually needed. Using the autoload mechanism is recommended:
Bram Moolenaara2baa732022-02-04 16:09:54 +00002105 *E1264*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010021061. In the plugin define user commands, functions and/or mappings that refer to
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002107 items imported from an autoload script. >
2108 import autoload 'for/search.vim'
2109 command -nargs=1 SearchForStuff search.Stuff(<f-args>)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002110
2111< This goes in .../plugin/anyname.vim. "anyname.vim" can be freely chosen.
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002112 The "SearchForStuff" command is now available to the user.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002113
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002114 The "autoload" argument to `:import` means that the script is not loaded
2115 until one of the items is actually used. The script will be found under
2116 the "autoload" directory in 'runtimepath' instead of the "import"
Bram Moolenaarcbaff5e2022-04-08 17:45:08 +01002117 directory. Alternatively a relative or absolute name can be used, see
2118 below.
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002119
21202. In the autoload script put the bulk of the code. >
Bram Moolenaarfd218c82022-01-18 16:26:24 +00002121 vim9script
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002122 export def Stuff(arg: string)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002123 ...
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002124
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002125< This goes in .../autoload/for/search.vim.
2126
Bram Moolenaarfd218c82022-01-18 16:26:24 +00002127 Putting the "search.vim" script under the "/autoload/for/" directory has
2128 the effect that "for#search#" will be prefixed to every exported item. The
2129 prefix is obtained from the file name, as you would to manually in a
2130 legacy autoload script. Thus the exported function can be found with
2131 "for#search#Stuff", but you would normally use `import autoload` and not
Bram Moolenaar47c532e2022-03-19 15:18:53 +00002132 use the prefix (which has the side effect of loading the autoload script
2133 when compiling a function that encounters this name).
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002134
2135 You can split up the functionality and import other scripts from the
2136 autoload script as you like. This way you can share code between plugins.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002137
Bram Moolenaarcbaff5e2022-04-08 17:45:08 +01002138Searching for the autoload script in all entries in 'runtimepath' can be a bit
2139slow. If the plugin knows where the script is located, quite often a relative
2140path can be used. This avoids the search and should be quite a bit faster.
2141Another advantage is that the script name does not need to be unique. An
2142absolute path is also possible. Examples: >
2143 import autoload '../lib/implement.vim'
2144 import autoload MyScriptsDir .. '/lib/implement.vim'
2145
Bram Moolenaarfd31be22022-01-16 14:46:06 +00002146For defining a mapping that uses the imported autoload script the special key
2147|<ScriptCmd>| is useful. It allows for a command in a mapping to use the
2148script context of where the mapping was defined.
2149
Bram Moolenaar418f1df2020-08-12 21:34:49 +02002150When compiling a `:def` function and a function in an autoload script is
2151encountered, the script is not loaded until the `:def` function is called.
Bram Moolenaardc4451d2022-01-09 21:36:37 +00002152This also means you get any errors only at runtime, since the argument and
Bram Moolenaar47c532e2022-03-19 15:18:53 +00002153return types are not known yet. If you would use the name with '#' characters
2154then the autoload script IS loaded.
2155
2156Be careful to not refer to an item in an autoload script that does trigger
2157loading it unintentionally. For example, when setting an option that takes a
2158function name, make sure to use a string, not a function reference: >
2159 import autoload 'qftf.vim'
2160 &quickfixtextfunc = 'qftf.Func' # autoload script NOT loaded
2161 &quickfixtextfunc = qftf.Func # autoload script IS loaded
2162On the other hand, it can be useful to load the script early, at a time when
2163any errors should be given.
Bram Moolenaar418f1df2020-08-12 21:34:49 +02002164
Bram Moolenaarfd31be22022-01-16 14:46:06 +00002165For testing the |test_override()| function can be used to have the
2166`import autoload` load the script right away, so that the items and types can
2167be checked without waiting for them to be actually used: >
2168 test_override('autoload', 1)
2169Reset it later with: >
2170 test_override('autoload', 0)
2171Or: >
2172 test_override('ALL', 0)
2173
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002174
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002175==============================================================================
2176
Bram Moolenaarc1c365c2022-12-04 20:13:24 +000021776. Classes and interfaces *vim9-classes*
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002178
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00002179In legacy script a Dictionary could be used as a kind-of object, by adding
2180members that are functions. However, this is quite inefficient and requires
2181the writer to do the work of making sure all the objects have the right
2182members. See |Dictionary-function|.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002183
Bram Moolenaarc1c365c2022-12-04 20:13:24 +00002184In |Vim9| script you can have classes, objects and interfaces like in most
2185popular object-oriented programming languages. Since this is a lot of
2186functionality it is located in a separate help file: |vim9class.txt|.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002187
Bram Moolenaar74235772021-06-12 14:53:05 +02002188
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002189==============================================================================
2190
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010021919. Rationale *vim9-rationale*
2192
2193The :def command ~
2194
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002195Plugin writers have asked for much faster Vim script. Investigations have
Bram Moolenaar560979e2020-02-04 22:53:05 +01002196shown that keeping the existing semantics of function calls make this close to
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002197impossible, because of the overhead involved with calling a function, setting
2198up the local function scope and executing lines. There are many details that
2199need to be handled, such as error messages and exceptions. The need to create
2200a dictionary for a: and l: scopes, the a:000 list and several others add too
2201much overhead that cannot be avoided.
2202
2203Therefore the `:def` method to define a new-style function had to be added,
2204which allows for a function with different semantics. Most things still work
2205as before, but some parts do not. A new way to define a function was
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002206considered the best way to separate the legacy style code from Vim9 style code.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002207
2208Using "def" to define a function comes from Python. Other languages use
2209"function" which clashes with legacy Vim script.
2210
2211
2212Type checking ~
2213
2214When compiling lines of Vim commands into instructions as much as possible
2215should be done at compile time. Postponing it to runtime makes the execution
2216slower and means mistakes are found only later. For example, when
2217encountering the "+" character and compiling this into a generic add
Bram Moolenaar98a29d02021-01-18 19:55:44 +01002218instruction, at runtime the instruction would have to inspect the type of the
2219arguments and decide what kind of addition to do. And when the type is
2220dictionary throw an error. If the types are known to be numbers then an "add
2221number" instruction can be used, which is faster. The error can be given at
2222compile time, no error handling is needed at runtime, since adding two numbers
2223cannot fail.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002224
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002225The syntax for types, using <type> for compound types, is similar to Java. It
2226is easy to understand and widely used. The type names are what were used in
2227Vim before, with some additions such as "void" and "bool".
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002228
2229
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002230Removing clutter and weirdness ~
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002231
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002232Once decided that `:def` functions have different syntax than legacy functions,
2233we are free to add improvements to make the code more familiar for users who
2234know popular programming languages. In other words: remove weird things that
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002235only Vim does.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002236
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002237We can also remove clutter, mainly things that were done to make Vim script
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002238backwards compatible with the good old Vi commands.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002239
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002240Examples:
Bram Moolenaar63f32602022-06-09 20:45:54 +01002241- Drop `:call` for calling a function and `:eval` for evaluating an
2242 expression.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002243- Drop using a leading backslash for line continuation, automatically figure
2244 out where an expression ends.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002245
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002246However, this does require that some things need to change:
2247- Comments start with # instead of ", to avoid confusing them with strings.
Bram Moolenaar63f32602022-06-09 20:45:54 +01002248 This is good anyway, it is also used by several popular languages.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002249- Ex command ranges need to be prefixed with a colon, to avoid confusion with
2250 expressions (single quote can be a string or a mark, "/" can be divide or a
2251 search command, etc.).
2252
2253Goal is to limit the differences. A good criteria is that when the old syntax
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002254is accidentally used you are very likely to get an error message.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002255
2256
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002257Syntax and semantics from popular languages ~
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002258
2259Script writers have complained that the Vim script syntax is unexpectedly
2260different from what they are used to. To reduce this complaint popular
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002261languages are used as an example. At the same time, we do not want to abandon
2262the well-known parts of legacy Vim script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002263
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002264For many things TypeScript is followed. It's a recent language that is
2265gaining popularity and has similarities with Vim script. It also has a
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002266mix of static typing (a variable always has a known value type) and dynamic
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002267typing (a variable can have different types, this changes at runtime). Since
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002268legacy Vim script is dynamically typed and a lot of existing functionality
2269(esp. builtin functions) depends on that, while static typing allows for much
2270faster execution, we need to have this mix in Vim9 script.
2271
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002272There is no intention to completely match TypeScript syntax and semantics. We
2273just want to take those parts that we can use for Vim and we expect Vim users
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002274will be happy with. TypeScript is a complex language with its own history,
2275advantages and disadvantages. To get an idea of the disadvantages read the
2276book: "JavaScript: The Good Parts". Or find the article "TypeScript: the good
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002277parts" and read the "Things to avoid" section.
2278
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002279People familiar with other languages (Java, Python, etc.) will also find
2280things in TypeScript that they do not like or do not understand. We'll try to
2281avoid those things.
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002282
2283Specific items from TypeScript we avoid:
2284- Overloading "+", using it both for addition and string concatenation. This
2285 goes against legacy Vim script and often leads to mistakes. For that reason
2286 we will keep using ".." for string concatenation. Lua also uses ".." this
2287 way. And it allows for conversion to string for more values.
2288- TypeScript can use an expression like "99 || 'yes'" in a condition, but
2289 cannot assign the value to a boolean. That is inconsistent and can be
2290 annoying. Vim recognizes an expression with && or || and allows using the
Bram Moolenaar1f318c62021-12-26 18:09:31 +00002291 result as a bool. The |falsy-operator| was added for the mechanism to use a
2292 default value.
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02002293- TypeScript considers an empty string as Falsy, but an empty list or dict as
2294 Truthy. That is inconsistent. In Vim an empty list and dict are also
2295 Falsy.
2296- TypeScript has various "Readonly" types, which have limited usefulness,
2297 since a type cast can remove the immutable nature. Vim locks the value,
2298 which is more flexible, but is only checked at runtime.
Bram Moolenaarf10911e2022-01-29 22:20:48 +00002299- TypeScript has a complicated "import" statement that does not match how the
2300 Vim import mechanism works. A much simpler mechanism is used instead, which
2301 matches that the imported script is only sourced once.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002302
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002303
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002304Declarations ~
2305
2306Legacy Vim script uses `:let` for every assignment, while in Vim9 declarations
2307are used. That is different, thus it's good to use a different command:
2308`:var`. This is used in many languages. The semantics might be slightly
2309different, but it's easily recognized as a declaration.
2310
Bram Moolenaar23515b42020-11-29 14:36:24 +01002311Using `:const` for constants is common, but the semantics varies. Some
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002312languages only make the variable immutable, others also make the value
2313immutable. Since "final" is well known from Java for only making the variable
2314immutable we decided to use that. And then `:const` can be used for making
2315both immutable. This was also used in legacy Vim script and the meaning is
2316almost the same.
2317
2318What we end up with is very similar to Dart: >
2319 :var name # mutable variable and value
2320 :final name # immutable variable, mutable value
2321 :const name # immutable variable and value
2322
2323Since legacy and Vim9 script will be mixed and global variables will be
2324shared, optional type checking is desirable. Also, type inference will avoid
2325the need for specifying the type in many cases. The TypeScript syntax fits
2326best for adding types to declarations: >
2327 var name: string # string type is specified
2328 ...
2329 name = 'John'
2330 const greeting = 'hello' # string type is inferred
2331
2332This is how we put types in a declaration: >
2333 var mylist: list<string>
2334 final mylist: list<string> = ['foo']
2335 def Func(arg1: number, arg2: string): bool
2336
2337Two alternatives were considered:
23381. Put the type before the name, like Dart: >
2339 var list<string> mylist
2340 final list<string> mylist = ['foo']
2341 def Func(number arg1, string arg2) bool
23422. Put the type after the variable name, but do not use a colon, like Go: >
2343 var mylist list<string>
2344 final mylist list<string> = ['foo']
2345 def Func(arg1 number, arg2 string) bool
2346
2347The first is more familiar for anyone used to C or Java. The second one
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +02002348doesn't really have an advantage over the first, so let's discard the second.
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002349
2350Since we use type inference the type can be left out when it can be inferred
2351from the value. This means that after `var` we don't know if a type or a name
2352follows. That makes parsing harder, not only for Vim but also for humans.
2353Also, it will not be allowed to use a variable name that could be a type name,
2354using `var string string` is too confusing.
2355
2356The chosen syntax, using a colon to separate the name from the type, adds
2357punctuation, but it actually makes it easier to recognize the parts of a
2358declaration.
2359
2360
2361Expressions ~
2362
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +02002363Expression evaluation was already close to what other languages are doing.
2364Some details are unexpected and can be improved. For example a boolean
2365condition would accept a string, convert it to a number and check if the
2366number is non-zero. This is unexpected and often leads to mistakes, since
2367text not starting with a number would be converted to zero, which is
Bram Moolenaarcb80aa22020-10-26 21:12:46 +01002368considered false. Thus using a string for a condition would often not give an
2369error and be considered false. That is confusing.
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002370
Bram Moolenaar23515b42020-11-29 14:36:24 +01002371In Vim9 type checking is stricter to avoid mistakes. Where a condition is
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +02002372used, e.g. with the `:if` command and the `||` operator, only boolean-like
2373values are accepted:
2374 true: `true`, `v:true`, `1`, `0 < 9`
2375 false: `false`, `v:false`, `0`, `0 > 9`
2376Note that the number zero is false and the number one is true. This is more
Bram Moolenaarcb80aa22020-10-26 21:12:46 +01002377permissive than most other languages. It was done because many builtin
Bram Moolenaar63f32602022-06-09 20:45:54 +01002378functions return these values, and changing that causes more problems than it
2379solves. After using this for a while it turned out to work well.
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002380
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +02002381If you have any type of value and want to use it as a boolean, use the `!!`
2382operator:
Bram Moolenaar63f32602022-06-09 20:45:54 +01002383 true: `!!'text'` `!![99]` `!!{'x': 1}` `!!99`
2384 false: `!!''` `!![]` `!!{}`
Bram Moolenaar4f4d51a2020-10-11 13:57:40 +02002385
2386From a language like JavaScript we have this handy construct: >
2387 GetName() || 'unknown'
2388However, this conflicts with only allowing a boolean for a condition.
2389Therefore the "??" operator was added: >
2390 GetName() ?? 'unknown'
2391Here you can explicitly express your intention to use the value as-is and not
2392result in a boolean. This is called the |falsy-operator|.
Bram Moolenaar30fd8202020-09-26 15:09:30 +02002393
2394
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002395Import and Export ~
2396
2397A problem of legacy Vim script is that by default all functions and variables
2398are global. It is possible to make them script-local, but then they are not
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002399available in other scripts. This defies the concept of a package that only
2400exports selected items and keeps the rest local.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002401
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02002402In Vim9 script a mechanism very similar to the JavaScript import and export
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002403mechanism is supported. It is a variant to the existing `:source` command
2404that works like one would expect:
2405- Instead of making everything global by default, everything is script-local,
Bram Moolenaar63f32602022-06-09 20:45:54 +01002406 some of these are exported.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002407- When importing a script the symbols that are imported are explicitly listed,
2408 avoiding name conflicts and failures if functionality is added later.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002409- The mechanism allows for writing a big, long script with a very clear API:
Bram Moolenaar63f32602022-06-09 20:45:54 +01002410 the exported functions, variables and classes.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002411- By using relative paths loading can be much faster for an import inside of a
2412 package, no need to search many directories.
Bram Moolenaar63f32602022-06-09 20:45:54 +01002413- Once an import has been used, its items are cached and loading it again is
2414 not needed.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002415- The Vim-specific use of "s:" to make things script-local can be dropped.
2416
Bram Moolenaar63f32602022-06-09 20:45:54 +01002417When sourcing a Vim9 script (from a Vim9 or legacy script), only the items
2418defined globally can be used, not the exported items. Alternatives
2419considered:
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002420- All the exported items become available as script-local items. This makes
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002421 it uncontrollable what items get defined and likely soon leads to trouble.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002422- Use the exported items and make them global. Disadvantage is that it's then
2423 not possible to avoid name clashes in the global namespace.
2424- Completely disallow sourcing a Vim9 script, require using `:import`. That
2425 makes it difficult to use scripts for testing, or sourcing them from the
2426 command line to try them out.
Bram Moolenaar63f32602022-06-09 20:45:54 +01002427Note that you CAN also use `:import` in legacy Vim script, see above.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02002428
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002429
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002430Compiling functions early ~
2431
2432Functions are compiled when called or when `:defcompile` is used. Why not
2433compile them early, so that syntax and type errors are reported early?
2434
2435The functions can't be compiled right away when encountered, because there may
2436be forward references to functions defined later. Consider defining functions
2437A, B and C, where A calls B, B calls C, and C calls A again. It's impossible
2438to reorder the functions to avoid forward references.
2439
2440An alternative would be to first scan through the file to locate items and
2441figure out their type, so that forward references are found, and only then
2442execute the script and compile the functions. This means the script has to be
2443parsed twice, which is slower, and some conditions at the script level, such
2444as checking if a feature is supported, are hard to use. An attempt was made
Bram Moolenaar63f32602022-06-09 20:45:54 +01002445to see if it works, but it turned out to be impossible to make work well.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002446
2447It would be possible to compile all the functions at the end of the script.
2448The drawback is that if a function never gets called, the overhead of
2449compiling it counts anyway. Since startup speed is very important, in most
2450cases it's better to do it later and accept that syntax and type errors are
2451only reported then. In case these errors should be found early, e.g. when
Bram Moolenaar63f32602022-06-09 20:45:54 +01002452testing, a `:defcompile` command at the end of the script will help out.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002453
2454
Bram Moolenaar63f32602022-06-09 20:45:54 +01002455Why not use an existing embedded language? ~
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002456
2457Vim supports interfaces to Perl, Python, Lua, Tcl and a few others. But
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002458these interfaces have never become widely used, for various reasons. When
2459Vim9 was designed a decision was made to make these interfaces lower priority
2460and concentrate on Vim script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002461
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002462Still, plugin writers may find other languages more familiar, want to use
2463existing libraries or see a performance benefit. We encourage plugin authors
Bram Moolenaar63f32602022-06-09 20:45:54 +01002464to write code in any language and run it as an external process, using jobs
2465and channels. We can try to make this easier somehow.
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002466
2467Using an external tool also has disadvantages. An alternative is to convert
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002468the tool into Vim script. For that to be possible without too much
2469translation, and keeping the code fast at the same time, the constructs of the
2470tool need to be supported. Since most languages support classes the lack of
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02002471support for classes in Vim is then a problem.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002472
Bram Moolenaar1d59aa12020-09-19 18:50:13 +02002473
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002474
Christian Brabandtec6e82a2025-03-06 21:01:26 +01002475 vim:tw=78:ts=8:noet:ft=help:norl: