blob: 71c454ae9496cad0c553c90d451da34e3e7d1404 [file] [log] [blame]
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +02001*vim9.txt* For Vim version 8.2. Last change: 2020 Sep 13
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01002
3
4 VIM REFERENCE MANUAL by Bram Moolenaar
5
6
7THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
8
Bram Moolenaar7ceefb32020-05-01 16:07:38 +02009Vim9 script commands and expressions. *vim9*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010010
11Most expression help is in |eval.txt|. This file is about the new syntax and
12features in Vim9 script.
13
14THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
15
16
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200171. What is Vim9 script? |vim9-script|
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100182. Differences |vim9-differences|
193. New style functions |fast-functions|
204. Types |vim9-types|
215. Namespace, Import and Export |vim9script|
22
239. Rationale |vim9-rationale|
24
25==============================================================================
26
271. What is Vim9 script? *vim9-script*
28
29THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
30
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020031Vim script has been growing over time, while preserving backwards
32compatibility. That means bad choices from the past often can't be changed
Bram Moolenaar73fef332020-06-21 22:12:03 +020033and compatibility with Vi restricts possible solutions. Execution is quite
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020034slow, each line is parsed every time it is executed.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010035
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020036The main goal of Vim9 script is to drastically improve performance. This is
37accomplished by compiling commands into instructions that can be efficiently
38executed. An increase in execution speed of 10 to 100 times can be expected.
39
40A secondary goal is to avoid Vim-specific constructs and get closer to
41commonly used programming languages, such as JavaScript, TypeScript and Java.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010042
43The performance improvements can only be achieved by not being 100% backwards
Bram Moolenaar388a5d42020-05-26 21:20:45 +020044compatible. For example, making function arguments available in the
45"a:" dictionary adds quite a lot of overhead. In a Vim9 function this
46dictionary is not available. Other differences are more subtle, such as how
47errors are handled.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010048
49The Vim9 script syntax and semantics are used in:
50- a function defined with the `:def` command
51- a script file where the first command is `vim9script`
Bram Moolenaar207f0092020-08-30 17:20:20 +020052- an autocommand defined in the context of these
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010053
54When using `:function` in a Vim9 script file the legacy syntax is used.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020055However, this can be confusing and is therefore discouraged.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010056
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020057Vim9 script and legacy Vim script can be mixed. There is no requirement to
58rewrite old scripts, they keep working as before.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010059
60==============================================================================
61
622. Differences from legacy Vim script *vim9-differences*
63
64THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
65
Bram Moolenaar2c330432020-04-13 14:41:35 +020066Comments starting with # ~
67
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +020068In legacy Vim script comments start with double quote. In Vim9 script
69comments start with #. >
70 # declarations
Bram Moolenaar73fef332020-06-21 22:12:03 +020071 let count = 0 # number of occurrences
Bram Moolenaar2c330432020-04-13 14:41:35 +020072
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +020073The reason is that a double quote can also be the start of a string. In many
Bram Moolenaar3d1cde82020-08-15 18:55:18 +020074places, especially halfway through an expression with a line break, it's hard
75to tell what the meaning is, since both a string and a comment can be followed
76by arbitrary text. To avoid confusion only # comments are recognized. This
77is the same as in shell scripts and Python programs.
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +020078
79In Vi # is a command to list text with numbers. In Vim9 script you can use
80`:number` for that. >
Bram Moolenaarae616492020-07-28 20:07:27 +020081 101 number
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +020082
83To improve readability there must be a space between a command and the #
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +020084that starts a comment. Note that #{ is the start of a dictionary, therefore
Bram Moolenaarae616492020-07-28 20:07:27 +020085it does not start a comment.
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +020086
Bram Moolenaar2c330432020-04-13 14:41:35 +020087
Bram Moolenaar8a7d6542020-01-26 15:56:19 +010088Vim9 functions ~
89
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020090A function defined with `:def` is compiled. Execution is many times faster,
91often 10x to 100x times.
92
Bram Moolenaar388a5d42020-05-26 21:20:45 +020093Many errors are already found when compiling, before the function is executed.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +020094The syntax is strict, to enforce code that is easy to read and understand.
95
Bram Moolenaar207f0092020-08-30 17:20:20 +020096Compilation is done when:
97- the function is first called
98- when the `:defcompile` command is encountered in the script where the
99 function was defined
100- `:disassemble` is used for the function.
101- a function that is compiled calls the function or uses it as a function
102 reference
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200103
104`:def` has no options like `:function` does: "range", "abort", "dict" or
105"closure". A `:def` function always aborts on an error, does not get a range
106passed and cannot be a "dict" function.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100107
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200108The argument types and return type need to be specified. The "any" type can
109be used, type checking will then be done at runtime, like with legacy
110functions.
111
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200112Arguments are accessed by name, without "a:", just like any other language.
113There is no "a:" dictionary or "a:000" list.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200114
115Variable arguments are defined as the last argument, with a name and have a
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200116list type, similar to TypeScript. For example, a list of numbers: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200117 def MyFunc(...itemlist: list<number>)
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100118 for item in itemlist
119 ...
120
121
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200122Functions and variables are script-local by default ~
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200123 *vim9-scopes*
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200124When using `:function` or `:def` to specify a new function at the script level
125in a Vim9 script, the function is local to the script, as if "s:" was
Bram Moolenaarea2d8d22020-07-29 22:11:05 +0200126prefixed. Using the "s:" prefix is optional. To define or use a global
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200127function or variable the "g:" prefix should be used. For functions in an
Bram Moolenaarea2d8d22020-07-29 22:11:05 +0200128autoload script the "name#" prefix is sufficient. >
129 def ThisFunction() # script-local
130 def s:ThisFunction() # script-local
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200131 def g:ThatFunction() # global
132 def ThatFunction() # global if no local ThatFunction()
Bram Moolenaarea2d8d22020-07-29 22:11:05 +0200133 def scriptname#function() # autoload
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200134
135When using `:function` or `:def` to specify a new function inside a function,
136the function is local to the function. It is not possible to define a
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200137script-local function inside a function. It is possible to define a global
138function, using the "g:" prefix.
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200139
140When referring to a function and no "s:" or "g:" prefix is used, Vim will
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200141prefer using a local function (in the function scope, script scope or
142imported) before looking for a global function.
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200143In all cases the function must be defined before used. That is when it is
144first called or when `:defcompile` causes the call to be compiled.
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200145
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200146The result is that functions and variables without a namespace can usually be
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200147found in the script, either defined there or imported. Global functions and
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200148variables could be defined anywhere (good luck finding out where!).
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200149
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200150Global functions can still be defined and deleted at nearly any time. In
Bram Moolenaar2cfb4a22020-05-07 18:56:00 +0200151Vim9 script script-local functions are defined once when the script is sourced
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200152and cannot be deleted or replaced.
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200153
154
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100155Variable declarations with :let and :const ~
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200156 *vim9-declaration*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100157Local variables need to be declared with `:let`. Local constants need to be
158declared with `:const`. We refer to both as "variables".
159
160Variables can be local to a script, function or code block: >
161 vim9script
162 let script_var = 123
163 def SomeFunc()
164 let func_var = script_var
165 if cond
166 let block_var = func_var
167 ...
168
169The variables are only visible in the block where they are defined and nested
170blocks. Once the block ends the variable is no longer accessible: >
171 if cond
172 let inner = 5
173 else
174 let inner = 0
175 endif
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200176 echo inner # Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100177
178The declaration must be done earlier: >
179 let inner: number
180 if cond
181 inner = 5
182 else
183 inner = 0
184 endif
185 echo inner
186
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200187To intentionally avoid a variable being available later, a block can be used:
188>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100189 {
190 let temp = 'temp'
191 ...
192 }
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200193 echo temp # Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100194
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200195Declaring a variable with a type but without an initializer will initialize to
196zero, false or empty.
197
Bram Moolenaar560979e2020-02-04 22:53:05 +0100198An existing variable cannot be assigned to with `:let`, since that implies a
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200199declaration. Global, window, tab, buffer and Vim variables can only be used
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200200without `:let`, because they are not really declared, they can also be deleted
201with `:unlet`.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100202
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200203Variables and functions cannot shadow previously defined or imported variables
204and functions.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100205Variables may shadow Ex commands, rename the variable if needed.
206
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200207Global variables and user defined functions must be prefixed with "g:", also
208at the script level. >
Bram Moolenaard1caa942020-04-10 22:10:56 +0200209 vim9script
210 let script_local = 'text'
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200211 g:global = 'value'
Bram Moolenaar7ceefb32020-05-01 16:07:38 +0200212 let Funcref = g:ThatFunction
Bram Moolenaard1caa942020-04-10 22:10:56 +0200213
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100214Since "&opt = value" is now assigning a value to option "opt", ":&" cannot be
215used to repeat a `:substitute` command.
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200216 *vim9-const*
217In legacy Vim script "const list = []" would make the variable "list"
218immutable and also the value. Thus you cannot add items to the list. This
219differs from what many languages do. Vim9 script does it like TypeScript: only
220"list" is immutable, the value can be changed.
221
222One can use `:const!` to make both the variable and the value immutable. Use
223this for composite structures that you want to make sure will not be modified.
224
225How this works: >
226 vim9script
227 const list = [1, 2]
228 list = [3, 4] # Error!
229 list[0] = 2 # OK
230
231 const! LIST = [1, 2]
232 LIST = [3, 4] # Error!
233 LIST[0] = 2 # Error!
234It is common to write constants as ALL_CAPS, but you don't have to.
235
236The constant only applies to the value itself, not what it refers to. >
237 cont females = ["Mary"]
238 const! NAMES = [["John", "Peter"], females]
239 NAMES[0] = ["Jack"] # Error!
240 NAMES[0][0] = ["Jack"] # Error!
241 NAMES[1] = ["Emma"] # Error!
242 Names[1][0] = "Emma" # OK, now females[0] == "Emma"
243
244Rationale: TypeScript has no way to make the value immutable. One can use
245immutable types, but that quickly gets complicated for nested values. And
246with a type cast the value can be made mutable again, which means there is no
247guarantee the value won't change. Vim supports immutable values, in legacy
248script this was done with `:lockvar`. But that is an extra statement and also
249applies to nested values. Therefore the solution to use `:const!`.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100250
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200251 *E1092*
252Declaring more than one variable at a time, using the unpack notation, is
253currently not supported: >
254 let [v1, v2] = GetValues() # Error!
255That is because the type needs to be inferred from the list item type, which
256isn't that easy.
257
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100258
259Omitting :call and :eval ~
260
261Functions can be called without `:call`: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200262 writefile(lines, 'file')
Bram Moolenaar560979e2020-02-04 22:53:05 +0100263Using `:call` is still possible, but this is discouraged.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100264
265A method call without `eval` is possible, so long as the start is an
Bram Moolenaarae616492020-07-28 20:07:27 +0200266identifier or can't be an Ex command. Examples: >
267 myList->add(123)
268 g:myList->add(123)
269 [1, 2, 3]->Process()
270 #{a: 1, b: 2}->Process()
271 {'a': 1, 'b': 2}->Process()
272 "foobar"->Process()
273 ("foobar")->Process()
274 'foobar'->Process()
275 ('foobar')->Process()
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100276
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200277In the rare case there is ambiguity between a function name and an Ex command,
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200278prepend ":" to make clear you want to use the Ex command. For example, there
279is both the `:substitute` command and the `substitute()` function. When the
280line starts with `substitute(` this will use the function. Prepend a colon to
281use the command instead: >
Bram Moolenaar0c6ceaf2020-02-22 18:36:32 +0100282 :substitute(pattern (replacement (
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100283
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100284Note that while variables need to be defined before they can be used,
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200285functions can be called before being defined. This is required to allow
286for cyclic dependencies between functions. It is slightly less efficient,
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100287since the function has to be looked up by name. And a typo in the function
Bram Moolenaarae616492020-07-28 20:07:27 +0200288name will only be found when the function is called.
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100289
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100290
Bram Moolenaard1caa942020-04-10 22:10:56 +0200291Omitting function() ~
292
293A user defined function can be used as a function reference in an expression
294without `function()`. The argument types and return type will then be checked.
295The function must already have been defined. >
296
297 let Funcref = MyFunction
298
299When using `function()` the resulting type is "func", a function with any
300number of arguments and any return type. The function can be defined later.
301
302
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200303Automatic line continuation ~
304
305In many cases it is obvious that an expression continues on the next line. In
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200306those cases there is no need to prefix the line with a backslash
307|line-continuation|. For example, when a list spans multiple lines: >
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200308 let mylist = [
309 'one',
310 'two',
311 ]
Bram Moolenaare6085c52020-04-12 20:19:16 +0200312And when a dict spans multiple lines: >
313 let mydict = #{
314 one: 1,
315 two: 2,
316 }
317Function call: >
318 let result = Func(
319 arg1,
320 arg2
321 )
322
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200323For binary operators in expressions not in [], {} or () a line break is
324possible just before or after the operator. For example: >
325 let text = lead
326 .. middle
327 .. end
Bram Moolenaar9c7e6dd2020-04-12 20:55:20 +0200328 let total = start +
329 end -
330 correction
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200331 let result = positive
332 ? PosFunc(arg)
333 : NegFunc(arg)
Bram Moolenaar9c7e6dd2020-04-12 20:55:20 +0200334
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200335For a method call using "->" and a member using a dot, a line break is allowed
336before it: >
Bram Moolenaar73fef332020-06-21 22:12:03 +0200337 let result = GetBuilder()
338 ->BuilderSetWidth(333)
339 ->BuilderSetHeight(777)
340 ->BuilderBuild()
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200341 let result = MyDict
342 .member
Bram Moolenaar73fef332020-06-21 22:12:03 +0200343
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200344< *E1050*
345To make it possible for the operator at the start of the line to be
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200346recognized, it is required to put a colon before a range. This will add
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200347"start" and print: >
348 let result = start
349 + print
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200350Like this: >
351 let result = start + print
352
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200353This will assign "start" and print a line: >
354 let result = start
355 :+ print
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200356
Bram Moolenaar5e774c72020-04-12 21:53:00 +0200357It is also possible to split a function header over multiple lines, in between
358arguments: >
359 def MyFunc(
360 text: string,
361 separator = '-'
362 ): string
363
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200364Notes:
365- "enddef" cannot be used at the start of a continuation line, it ends the
366 current function.
367- No line break is allowed in the LHS of an assignment. Specifically when
368 unpacking a list |:let-unpack|. This is OK: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200369 [var1, var2] =
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200370 Func()
371< This does not work: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200372 [var1,
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200373 var2] =
374 Func()
375- No line break is allowed in between arguments of an `:echo`, `:execute` and
376 similar commands. This is OK: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200377 echo [1,
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200378 2] [3,
379 4]
380< This does not work: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200381 echo [1, 2]
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200382 [3, 4]
383- No line break is allowed in the arguments of a lambda, between the "{" and
384 "->". This is OK: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200385 filter(list, {k, v ->
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200386 v > 0})
387< This does not work: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200388 filter(list, {k,
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200389 v -> v > 0})
Bram Moolenaardf069ee2020-06-22 23:02:51 +0200390
Bram Moolenaar4fdae992020-04-12 16:38:57 +0200391
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100392No curly braces expansion ~
393
394|curly-braces-names| cannot be used.
395
396
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200397No :xit, :t, :append, :change or :insert ~
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100398
Bram Moolenaarf5a48012020-08-01 17:00:03 +0200399These commands are too easily confused with local variable names.
400Instead of `:x` or `:xit` you can use `:exit`.
401Instead of `:t` you can use `:copy`.
Bram Moolenaar560979e2020-02-04 22:53:05 +0100402
403
404Comparators ~
405
406The 'ignorecase' option is not used for comparators that use strings.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100407
408
409White space ~
410
411Vim9 script enforces proper use of white space. This is no longer allowed: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200412 let var=234 # Error!
413 let var= 234 # Error!
414 let var =234 # Error!
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100415There must be white space before and after the "=": >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200416 let var = 234 # OK
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200417White space must also be put before the # that starts a comment after a
418command: >
Bram Moolenaar2c330432020-04-13 14:41:35 +0200419 let var = 234# Error!
420 let var = 234 # OK
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100421
422White space is required around most operators.
423
424White space is not allowed:
425- Between a function name and the "(": >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200426 call Func (arg) # Error!
427 call Func
428 \ (arg) # Error!
429 call Func(arg) # OK
430 call Func(
431 \ arg) # OK
432 call Func(
433 \ arg # OK
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100434 \ )
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100435
436
437Conditions and expressions ~
438
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200439Conditions and expressions are mostly working like they do in JavaScript. A
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100440difference is made where JavaScript does not work like most people expect.
441Specifically, an empty list is falsey.
442
443Any type of variable can be used as a condition, there is no error, not even
444for using a list or job. This is very much like JavaScript, but there are a
445few exceptions.
446
447 type TRUE when ~
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200448 bool v:true or 1
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100449 number non-zero
450 float non-zero
451 string non-empty
452 blob non-empty
453 list non-empty (different from JavaScript)
454 dictionary non-empty (different from JavaScript)
Bram Moolenaard1caa942020-04-10 22:10:56 +0200455 func when there is a function name
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100456 special v:true
457 job when not NULL
458 channel when not NULL
459 class when not NULL
460 object when not NULL (TODO: when isTrue() returns v:true)
461
462The boolean operators "||" and "&&" do not change the value: >
463 8 || 2 == 8
464 0 || 2 == 2
465 0 || '' == ''
466 8 && 2 == 2
467 0 && 2 == 0
Bram Moolenaarf5be8cd2020-07-17 20:36:00 +0200468 2 && 0 == 0
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100469 [] && 2 == []
470
Bram Moolenaar418f1df2020-08-12 21:34:49 +0200471When using `..` for string concatenation arguments of simple types are always
472converted to string. >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100473 'hello ' .. 123 == 'hello 123'
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200474 'hello ' .. v:true == 'hello v:true'
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100475
Bram Moolenaar418f1df2020-08-12 21:34:49 +0200476Simple types are string, float, special and bool. For other types |string()|
477can be used.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200478 *false* *true*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100479In Vim9 script one can use "true" for v:true and "false" for v:false.
480
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200481Indexing a string with [idx] or [idx, idx] uses character indexes instead of
482byte indexes. Example: >
483 echo 'bár'[1]
484In legacy script this results in the character 0xc3 (an illegal byte), in Vim9
485script this results in the string 'á'.
486
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100487
Bram Moolenaare46a4402020-06-30 20:38:27 +0200488What to watch out for ~
489 *vim9-gotchas*
490Vim9 was designed to be closer to often used programming languages, but at the
491same time tries to support the legacy Vim commands. Some compromises had to
492be made. Here is a summary of what might be unexpected.
493
494Ex command ranges need to be prefixed with a colon. >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200495 -> # legacy Vim: shifts the previous line to the right
496 ->func() # Vim9: method call in continuation line
497 :-> # Vim9: shifts the previous line to the right
Bram Moolenaare46a4402020-06-30 20:38:27 +0200498
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200499 %s/a/b # legacy Vim: substitute on all lines
Bram Moolenaare46a4402020-06-30 20:38:27 +0200500 x = alongname
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200501 % another # Vim9: line continuation without a backslash
502 :%s/a/b # Vim9: substitute on all lines
503 'text'->func() # Vim9: method call
504 :'t # legacy Vim: jump to mark m
Bram Moolenaare46a4402020-06-30 20:38:27 +0200505
Bram Moolenaare7b1ea02020-08-07 19:54:59 +0200506Some Ex commands can be confused with assignments in Vim9 script: >
507 g:name = value # assignment
508 g:pattern:cmd # invalid command - ERROR
509 :g:pattern:cmd # :global command
510
Bram Moolenaare46a4402020-06-30 20:38:27 +0200511Functions defined with `:def` compile the whole function. Legacy functions
512can bail out, and the following lines are not parsed: >
513 func Maybe()
514 if !has('feature')
515 return
516 endif
517 use-feature
518 endfunc
519Vim9 functions are compiled as a whole: >
520 def Maybe()
521 if !has('feature')
522 return
523 endif
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200524 use-feature # May give compilation error
Bram Moolenaare46a4402020-06-30 20:38:27 +0200525 enddef
526For a workaround, split it in two functions: >
527 func Maybe()
528 if has('feature')
529 call MaybyInner()
530 endif
531 endfunc
532 if has('feature')
533 def MaybeInner()
534 use-feature
535 enddef
536 endif
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200537Or put the unsupported code inside an `if` with a constant expression that
Bram Moolenaar207f0092020-08-30 17:20:20 +0200538evaluates to false: >
539 def Maybe()
540 if has('feature')
541 use-feature
542 endif
543 enddef
544Note that for unrecognized commands there is no check for "|" and a following
545command. This will give an error for missing `endif`: >
546 def Maybe()
547 if has('feature') | use-feature | endif
548 enddef
Bram Moolenaare46a4402020-06-30 20:38:27 +0200549
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100550==============================================================================
551
5523. New style functions *fast-functions*
553
554THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
555
556 *:def*
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200557:def[!] {name}([arguments])[: {return-type}]
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100558 Define a new function by the name {name}. The body of
559 the function follows in the next lines, until the
560 matching `:enddef`.
561
Bram Moolenaard77a8522020-04-03 21:59:57 +0200562 When {return-type} is omitted or is "void" the
563 function is not expected to return anything.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100564
565 {arguments} is a sequence of zero or more argument
566 declarations. There are three forms:
567 {name}: {type}
568 {name} = {value}
569 {name}: {type} = {value}
570 The first form is a mandatory argument, the caller
571 must always provide them.
572 The second and third form are optional arguments.
573 When the caller omits an argument the {value} is used.
574
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200575 The function will be compiled into instructions when
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200576 called, or when `:disassemble` or `:defcompile` is
577 used. Syntax and type errors will be produced at that
578 time.
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200579
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200580 It is possible to nest `:def` inside another `:def` or
581 `:function` up to about 50 levels deep.
Bram Moolenaar560979e2020-02-04 22:53:05 +0100582
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200583 [!] is used as with `:function`. Note that in Vim9
584 script script-local functions cannot be deleted or
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200585 redefined later in the same script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100586
587 *:enddef*
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200588:enddef End of a function defined with `:def`. It should be on
589 a line by its own.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100590
591
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100592If the script the function is defined in is Vim9 script, then script-local
593variables can be accessed without the "s:" prefix. They must be defined
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200594before the function is compiled. If the script the function is defined in is
595legacy script, then script-local variables must be accessed with the "s:"
Bram Moolenaar207f0092020-08-30 17:20:20 +0200596prefix and they do not need to exist (they can be deleted any time).
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100597
Bram Moolenaar388a5d42020-05-26 21:20:45 +0200598 *:defc* *:defcompile*
599:defc[ompile] Compile functions defined in the current script that
600 were not compiled yet.
601 This will report errors found during the compilation.
Bram Moolenaar5b1c8fe2020-02-21 18:42:43 +0100602
Bram Moolenaarebdf3c92020-02-15 21:41:42 +0100603 *:disa* *:disassemble*
604:disa[ssemble] {func} Show the instructions generated for {func}.
605 This is for debugging and testing.
Bram Moolenaarcc390ff2020-02-29 22:06:30 +0100606 Note that for command line completion of {func} you
607 can prepend "s:" to find script-local functions.
Bram Moolenaarebdf3c92020-02-15 21:41:42 +0100608
Bram Moolenaar7ff78462020-07-10 22:00:53 +0200609Limitations ~
610
611Local variables will not be visible to string evaluation. For example: >
612 def EvalString(): list<string>
613 let list = ['aa', 'bb', 'cc', 'dd']
614 return range(1, 2)->map('list[v:val]')
615 enddef
616
617The map argument is a string expression, which is evaluated without the
618function scope. Instead, use a lambda: >
619 def EvalString(): list<string>
620 let list = ['aa', 'bb', 'cc', 'dd']
621 return range(1, 2)->map({ _, v -> list[v] })
622 enddef
623
624
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100625==============================================================================
626
6274. Types *vim9-types*
628
629THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
630
631The following builtin types are supported:
632 bool
633 number
634 float
635 string
636 blob
Bram Moolenaard77a8522020-04-03 21:59:57 +0200637 list<{type}>
638 dict<{type}>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100639 job
640 channel
Bram Moolenaarb17893a2020-03-14 08:19:51 +0100641 func
Bram Moolenaard1caa942020-04-10 22:10:56 +0200642 func: {type}
Bram Moolenaard77a8522020-04-03 21:59:57 +0200643 func({type}, ...)
644 func({type}, ...): {type}
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100645
646Not supported yet:
Bram Moolenaard77a8522020-04-03 21:59:57 +0200647 tuple<a: {type}, b: {type}, ...>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100648
Bram Moolenaard77a8522020-04-03 21:59:57 +0200649These types can be used in declarations, but no value will have this type:
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200650 {type}|{type} {not implemented yet}
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100651 void
652 any
653
Bram Moolenaard77a8522020-04-03 21:59:57 +0200654There is no array type, use list<{type}> instead. For a list constant an
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100655efficient implementation is used that avoids allocating lot of small pieces of
656memory.
657
Bram Moolenaard77a8522020-04-03 21:59:57 +0200658A partial and function can be declared in more or less specific ways:
659func any kind of function reference, no type
Bram Moolenaard1caa942020-04-10 22:10:56 +0200660 checking for arguments or return value
Bram Moolenaard77a8522020-04-03 21:59:57 +0200661func: {type} any number and type of arguments with specific
662 return type
Bram Moolenaard1caa942020-04-10 22:10:56 +0200663func({type}) function with argument type, does not return
Bram Moolenaard77a8522020-04-03 21:59:57 +0200664 a value
Bram Moolenaard1caa942020-04-10 22:10:56 +0200665func({type}): {type} function with argument type and return type
666func(?{type}) function with type of optional argument, does
667 not return a value
668func(...{type}) function with type of variable number of
669 arguments, does not return a value
670func({type}, ?{type}, ...{type}): {type}
671 function with:
672 - type of mandatory argument
673 - type of optional argument
674 - type of variable number of arguments
675 - return type
Bram Moolenaard77a8522020-04-03 21:59:57 +0200676
677If the return type is "void" the function does not return a value.
678
679The reference can also be a |Partial|, in which case it stores extra arguments
680and/or a dictionary, which are not visible to the caller. Since they are
681called in the same way the declaration is the same.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100682
683Custom types can be defined with `:type`: >
684 :type MyList list<string>
Bram Moolenaar127542b2020-08-09 17:22:04 +0200685Custom types must start with a capital letter, to avoid name clashes with
686builtin types added later, similarly to user functions.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100687{not implemented yet}
688
689And classes and interfaces can be used as types: >
690 :class MyClass
691 :let mine: MyClass
692
693 :interface MyInterface
694 :let mine: MyInterface
695
696 :class MyTemplate<Targ>
697 :let mine: MyTemplate<number>
698 :let mine: MyTemplate<string>
699
700 :class MyInterface<Targ>
701 :let mine: MyInterface<number>
702 :let mine: MyInterface<string>
703{not implemented yet}
704
705
Bram Moolenaar64d662d2020-08-09 19:02:50 +0200706Variable types and type casting *variable-types*
707
708Variables declared in Vim9 script or in a `:def` function have a type, either
709specified explicitly or inferred from the initialization.
710
711Global, buffer, window and tab page variables do not have a specific type, the
712value can be changed at any time, possibly changing the type. Therefore, in
713compiled code the "any" type is assumed.
714
715This can be a problem when the "any" type is undesired and the actual type is
716expected to always be the same. For example, when declaring a list: >
717 let l: list<number> = [1, g:two]
718This will give an error, because "g:two" has type "any". To avoid this, use a
719type cast: >
720 let l: list<number> = [1, <number>g:two]
721< *type-casting*
722The compiled code will then check that "g:two" is a number at runtime and give
723an error if it isn't. This is called type casting.
724
725The syntax of a type cast is: "<" {type} ">". There cannot be white space
726after the "<" or before the ">" (to avoid them being confused with
727smaller-than and bigger-than operators).
728
729The semantics is that, if needed, a runtime type check is performed. The
730value is not actually changed. If you need to change the type, e.g. to change
731it to a string, use the |string()| function. Or use |str2nr()| to convert a
732string to a number.
733
734
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100735Type inference *type-inference*
736
737In general: Whenever the type is clear it can be omitted. For example, when
738declaring a variable and giving it a value: >
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200739 let var = 0 # infers number type
740 let var = 'hello' # infers string type
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100741
Bram Moolenaar127542b2020-08-09 17:22:04 +0200742The type of a list and dictionary comes from the common type of the values.
743If the values all have the same type, that type is used for the list or
744dictionary. If there is a mix of types, the "any" type is used. >
745 [1, 2, 3] list<number>
746 ['a', 'b', 'c'] list<string>
747 [1, 'x', 3] list<any>
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100748
Bram Moolenaar207f0092020-08-30 17:20:20 +0200749
750Stricter type checking *type-checking*
751
752In legacy Vim script, where a number was expected, a string would be
753automatically converted to a number. This was convenient for an actual number
754such as "123", but leads to unexpected problems (but no error message) if the
755string doesn't start with a number. Quite often this leads to hard-to-find
756bugs.
757
758In Vim9 script this has been made stricter. In most places it works just as
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200759before, if the value used matches the expected type. There will sometimes be
760an error, thus breaking backwards compatibility. For example:
Bram Moolenaar207f0092020-08-30 17:20:20 +0200761- Using a number other than 0 or 1 where a boolean is expected. *E1023*
762- Using a string value when setting a number options.
763- Using a number where a string is expected. *E1024*
764
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100765==============================================================================
766
7675. Namespace, Import and Export
768 *vim9script* *vim9-export* *vim9-import*
769
770THIS IS STILL UNDER DEVELOPMENT - ANYTHING CAN BREAK - ANYTHING CAN CHANGE
771
772A Vim9 script can be written to be imported. This means that everything in
773the script is local, unless exported. Those exported items, and only those
774items, can then be imported in another script.
775
Bram Moolenaar207f0092020-08-30 17:20:20 +0200776You can cheat by using the global namespace explicitly. We will assume here
777that you don't do that.
778
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100779
780Namespace ~
781 *:vim9script* *:vim9*
Bram Moolenaar560979e2020-02-04 22:53:05 +0100782To recognize a file that can be imported the `vim9script` statement must
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100783appear as the first statement in the file. It tells Vim to interpret the
784script in its own namespace, instead of the global namespace. If a file
785starts with: >
786 vim9script
787 let myvar = 'yes'
788Then "myvar" will only exist in this file. While without `vim9script` it would
789be available as `g:myvar` from any other script and function.
790
791The variables at the file level are very much like the script-local "s:"
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200792variables in legacy Vim script, but the "s:" is omitted. And they cannot be
793deleted.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100794
Bram Moolenaar2c7f8c52020-04-20 19:52:53 +0200795In Vim9 script the global "g:" namespace can still be used as before. And the
796"w:", "b:" and "t:" namespaces. These have in common that variables are not
797declared and they can be deleted.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100798
799A side effect of `:vim9script` is that the 'cpoptions' option is set to the
800Vim default value, like with: >
801 :set cpo&vim
802One of the effects is that |line-continuation| is always enabled.
803The original value of 'cpoptions' is restored at the end of the script.
804
805
806Export ~
807 *:export* *:exp*
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200808Exporting an item can be written as: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100809 export const EXPORTED_CONST = 1234
810 export let someValue = ...
811 export def MyFunc() ...
812 export class MyClass ...
813
814As this suggests, only constants, variables, `:def` functions and classes can
Bram Moolenaar2547aa92020-07-26 17:00:44 +0200815be exported. {classes are not implemented yet}
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100816
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200817 *E1042*
818`:export` can only be used in Vim9 script, at the script level.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100819
820
821Import ~
Bram Moolenaar73fef332020-06-21 22:12:03 +0200822 *:import* *:imp* *E1094*
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100823The exported items can be imported individually in another Vim9 script: >
824 import EXPORTED_CONST from "thatscript.vim"
825 import MyClass from "myclass.vim"
826
827To import multiple items at the same time: >
828 import {someValue, MyClass} from "thatscript.vim"
829
Bram Moolenaar560979e2020-02-04 22:53:05 +0100830In case the name is ambiguous, another name can be specified: >
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100831 import MyClass as ThatClass from "myclass.vim"
832 import {someValue, MyClass as ThatClass} from "myclass.vim"
833
834To import all exported items under a specific identifier: >
835 import * as That from 'thatscript.vim'
836
837Then you can use "That.EXPORTED_CONST", "That.someValue", etc. You are free
838to choose the name "That", but it is highly recommended to use the name of the
839script file to avoid confusion.
840
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200841`:import` can also be used in legacy Vim script. The imported items still
842become script-local, even when the "s:" prefix is not given.
843
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100844The script name after `import` can be:
845- A relative path, starting "." or "..". This finds a file relative to the
846 location of the script file itself. This is useful to split up a large
847 plugin into several files.
848- An absolute path, starting with "/" on Unix or "D:/" on MS-Windows. This
849 will be rarely used.
850- A path not being relative or absolute. This will be found in the
851 "import" subdirectories of 'runtimepath' entries. The name will usually be
852 longer and unique, to avoid loading the wrong file.
853
854Once a vim9 script file has been imported, the result is cached and used the
855next time the same script is imported. It will not be read again.
856 *:import-cycle*
857The `import` commands are executed when encountered. If that script (directly
858or indirectly) imports the current script, then items defined after the
859`import` won't be processed yet. Therefore cyclic imports can exist, but may
860result in undefined items.
861
862
863Import in an autoload script ~
864
865For optimal startup speed, loading scripts should be postponed until they are
Bram Moolenaar560979e2020-02-04 22:53:05 +0100866actually needed. A recommended mechanism:
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100867
8681. In the plugin define user commands, functions and/or mappings that refer to
869 an autoload script. >
870 command -nargs=1 SearchForStuff call searchfor#Stuff(<f-args>)
871
872< This goes in .../plugin/anyname.vim. "anyname.vim" can be freely chosen.
873
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02008742. In the autoload script do the actual work. You can import items from
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100875 other files to split up functionality in appropriate pieces. >
876 vim9script
877 import FilterFunc from "../import/someother.vim"
878 def searchfor#Stuff(arg: string)
879 let filtered = FilterFunc(arg)
880 ...
881< This goes in .../autoload/searchfor.vim. "searchfor" in the file name
882 must be exactly the same as the prefix for the function name, that is how
883 Vim finds the file.
884
8853. Other functionality, possibly shared between plugins, contains the exported
886 items and any private items. >
887 vim9script
888 let localVar = 'local'
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200889 export def FilterFunc(arg: string): string
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100890 ...
891< This goes in .../import/someother.vim.
892
Bram Moolenaar418f1df2020-08-12 21:34:49 +0200893When compiling a `:def` function and a function in an autoload script is
894encountered, the script is not loaded until the `:def` function is called.
895
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100896
897Import in legacy Vim script ~
898
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200899If an `import` statement is used in legacy Vim script, the script-local "s:"
900namespace will be used for the imported item, even when "s:" is not specified.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100901
902
903==============================================================================
904
9059. Rationale *vim9-rationale*
906
907The :def command ~
908
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200909Plugin writers have asked for a much faster Vim script. Investigations have
Bram Moolenaar560979e2020-02-04 22:53:05 +0100910shown that keeping the existing semantics of function calls make this close to
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100911impossible, because of the overhead involved with calling a function, setting
912up the local function scope and executing lines. There are many details that
913need to be handled, such as error messages and exceptions. The need to create
914a dictionary for a: and l: scopes, the a:000 list and several others add too
915much overhead that cannot be avoided.
916
917Therefore the `:def` method to define a new-style function had to be added,
918which allows for a function with different semantics. Most things still work
919as before, but some parts do not. A new way to define a function was
920considered the best way to separate the old-style code from Vim9 script code.
921
922Using "def" to define a function comes from Python. Other languages use
923"function" which clashes with legacy Vim script.
924
925
926Type checking ~
927
928When compiling lines of Vim commands into instructions as much as possible
929should be done at compile time. Postponing it to runtime makes the execution
930slower and means mistakes are found only later. For example, when
931encountering the "+" character and compiling this into a generic add
932instruction, at execution time the instruction would have to inspect the type
933of the arguments and decide what kind of addition to do. And when the
934type is dictionary throw an error. If the types are known to be numbers then
935an "add number" instruction can be used, which is faster. The error can be
936given at compile time, no error handling is needed at runtime.
937
938The syntax for types is similar to Java, since it is easy to understand and
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200939widely used. The type names are what were used in Vim before, with some
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100940additions such as "void" and "bool".
941
942
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200943Compiling functions early ~
944
945Functions are compiled when called or when `:defcompile` is used. Why not
946compile them early, so that syntax and type errors are reported early?
947
948The functions can't be compiled right away when encountered, because there may
949be forward references to functions defined later. Consider defining functions
950A, B and C, where A calls B, B calls C, and C calls A again. It's impossible
951to reorder the functions to avoid forward references.
952
953An alternative would be to first scan through the file to locate items and
Bram Moolenaar73fef332020-06-21 22:12:03 +0200954figure out their type, so that forward references are found, and only then
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200955execute the script and compile the functions. This means the script has to be
956parsed twice, which is slower, and some conditions at the script level, such
957as checking if a feature is supported, are hard to use. An attempt was made
958to see if it works, but it turned out to be impossible to make work nicely.
959
960It would be possible to compile all the functions at the end of the script.
961The drawback is that if a function never gets called, the overhead of
962compiling it counts anyway. Since startup speed is very important, in most
963cases it's better to do it later and accept that syntax and type errors are
964only reported then. In case these errors should be found early, e.g. when
965testing, the `:defcompile` command will help out.
966
967
968TypeScript syntax and semantics ~
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100969
970Script writers have complained that the Vim script syntax is unexpectedly
971different from what they are used to. To reduce this complaint popular
Bram Moolenaar65e0d772020-06-14 17:29:55 +0200972languages are used as an example. At the same time, we do not want to abandon
973the well-known parts of legacy Vim script.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100974
975Since Vim already uses `:let` and `:const` and optional type checking is
976desirable, the JavaScript/TypeScript syntax fits best for variable
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200977declarations: >
978 const greeting = 'hello' # string type is inferred
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100979 let name: string
980 ...
981 name = 'John'
982
983Expression evaluation was already close to what JavaScript and other languages
984are doing. Some details are unexpected and can be fixed. For example how the
985|| and && operators work. Legacy Vim script: >
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200986 let value = 44
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100987 ...
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200988 let result = value || 0 # result == 1
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100989
Bram Moolenaar3d1cde82020-08-15 18:55:18 +0200990Vim9 script works like JavaScript/TypeScript, keep the value: >
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200991 let value = 44
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100992 ...
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200993 let result = value || 0 # result == 44
Bram Moolenaar8a7d6542020-01-26 15:56:19 +0100994
Bram Moolenaar1c6737b2020-09-07 22:18:52 +0200995There is no intention to completely match TypeScript syntax and semantics. We
996just want to take those parts that we can use for Vim and we expect Vim users
Bram Moolenaar0b4c66c2020-09-14 21:39:44 +0200997will be happy with. TypeScript is a complex language with its own advantages
998and disadvantages. To get an idea of the disadvantages read the book:
999"JavaScript: The Good Parts". Or find the article "TypeScript: the good
1000parts" and read the "Things to avoid" section.
1001
1002People used to other languages (Java, Python, etc.) will also find things in
1003TypeScript that they do not like or do not understand. We'll try to avoid
1004those things.
1005
1006Specific items from TypeScript we avoid:
1007- Overloading "+", using it both for addition and string concatenation. This
1008 goes against legacy Vim script and often leads to mistakes. For that reason
1009 we will keep using ".." for string concatenation. Lua also uses ".." this
1010 way. And it allows for conversion to string for more values.
1011- TypeScript can use an expression like "99 || 'yes'" in a condition, but
1012 cannot assign the value to a boolean. That is inconsistent and can be
1013 annoying. Vim recognizes an expression with && or || and allows using the
1014 result as a bool.
1015- TypeScript considers an empty string as Falsy, but an empty list or dict as
1016 Truthy. That is inconsistent. In Vim an empty list and dict are also
1017 Falsy.
1018- TypeScript has various "Readonly" types, which have limited usefulness,
1019 since a type cast can remove the immutable nature. Vim locks the value,
1020 which is more flexible, but is only checked at runtime.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001021
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001022
1023Import and Export ~
1024
1025A problem of legacy Vim script is that by default all functions and variables
1026are global. It is possible to make them script-local, but then they are not
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001027available in other scripts. This defies the concept of a package that only
1028exports selected items and keeps the rest local.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001029
Bram Moolenaar3d1cde82020-08-15 18:55:18 +02001030In Vim9 script a mechanism very similar to the JavaScript import and export
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001031mechanism is supported. It is a variant to the existing `:source` command
1032that works like one would expect:
1033- Instead of making everything global by default, everything is script-local,
1034 unless exported.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001035- When importing a script the symbols that are imported are explicitly listed,
1036 avoiding name conflicts and failures if functionality is added later.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001037- The mechanism allows for writing a big, long script with a very clear API:
1038 the exported function(s) and class(es).
1039- By using relative paths loading can be much faster for an import inside of a
1040 package, no need to search many directories.
1041- Once an import has been used, it can be cached and loading it again can be
1042 avoided.
1043- The Vim-specific use of "s:" to make things script-local can be dropped.
1044
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001045When sourcing a Vim9 script from a legacy script, only the items defined
1046globally can be used, not the exported items. Alternatives considered:
1047- All the exported items become available as script-local items. This makes
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001048 it uncontrollable what items get defined and likely soon leads to trouble.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001049- Use the exported items and make them global. Disadvantage is that it's then
1050 not possible to avoid name clashes in the global namespace.
1051- Completely disallow sourcing a Vim9 script, require using `:import`. That
1052 makes it difficult to use scripts for testing, or sourcing them from the
1053 command line to try them out.
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001054Note that you can also use `:import` in legacy Vim script, see above.
Bram Moolenaar65e0d772020-06-14 17:29:55 +02001055
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001056
1057Classes ~
1058
1059Vim supports interfaces to Perl, Python, Lua, Tcl and a few others. But
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001060these interfaces have never become widespread. When Vim 9 was designed a
1061decision was made to phase out these interfaces and concentrate on Vim script,
1062while encouraging plugin authors to write code in any language and run it as
1063an external tool, using jobs and channels.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001064
1065Still, using an external tool has disadvantages. An alternative is to convert
1066the tool into Vim script. For that to be possible without too much
1067translation, and keeping the code fast at the same time, the constructs of the
1068tool need to be supported. Since most languages support classes the lack of
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001069support for classes in Vim is then a problem.
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001070
1071Previously Vim supported a kind-of object oriented programming by adding
1072methods to a dictionary. With some care this could be made to work, but it
1073does not look like real classes. On top of that, it's very slow, because of
1074the use of dictionaries.
1075
1076The support of classes in Vim9 script is a "minimal common functionality" of
Bram Moolenaar1c6737b2020-09-07 22:18:52 +02001077class support in most languages. It works much like Java, which is the most
Bram Moolenaar8a7d6542020-01-26 15:56:19 +01001078popular programming language.
1079
1080
1081
1082 vim:tw=78:ts=8:noet:ft=help:norl: