From: Peter Kenny Date: Mon, 10 Nov 2025 20:29:08 +0000 (+0000) Subject: runtime(doc): Update Section 4 of vim9.txt X-Git-Tag: v9.1.1905~4 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=54cc8201291e6f8860084ce7e7cd5b8069344612;p=thirdparty%2Fvim.git runtime(doc): Update Section 4 of vim9.txt closes: #18610 Signed-off-by: Peter Kenny Signed-off-by: Christian Brabandt --- diff --git a/runtime/doc/tags b/runtime/doc/tags index 8fd8cbae16..6feb92b2ae 100644 --- a/runtime/doc/tags +++ b/runtime/doc/tags @@ -8696,6 +8696,7 @@ instanceof() builtin.txt /*instanceof()* intel-itanium syntax.txt /*intel-itanium* intellimouse-wheel-problems gui_w32.txt /*intellimouse-wheel-problems* interactive-functions usr_41.txt /*interactive-functions* +interface vim9class.txt /*interface* interfaces-5.2 version5.txt /*interfaces-5.2* internal-error message.txt /*internal-error* internal-variables eval.txt /*internal-variables* @@ -11595,6 +11596,7 @@ vim9-access-modes vim9class.txt /*vim9-access-modes* vim9-autoload vim9.txt /*vim9-autoload* vim9-boolean vim9.txt /*vim9-boolean* vim9-class vim9class.txt /*vim9-class* +vim9-class-type vim9.txt /*vim9-class-type* vim9-classes vim9.txt /*vim9-classes* vim9-const vim9.txt /*vim9-const* vim9-curly vim9.txt /*vim9-curly* @@ -11602,14 +11604,18 @@ vim9-debug repeat.txt /*vim9-debug* vim9-declaration vim9.txt /*vim9-declaration* vim9-declarations usr_41.txt /*vim9-declarations* vim9-differences vim9.txt /*vim9-differences* +vim9-enum-type vim9.txt /*vim9-enum-type* +vim9-enumvalue-type vim9.txt /*vim9-enumvalue-type* vim9-export vim9.txt /*vim9-export* vim9-false-true vim9.txt /*vim9-false-true* vim9-final vim9.txt /*vim9-final* vim9-func-declaration vim9.txt /*vim9-func-declaration* +vim9-func-type vim9.txt /*vim9-func-type* vim9-function-defined-later vim9.txt /*vim9-function-defined-later* vim9-gotchas vim9.txt /*vim9-gotchas* vim9-ignored-argument vim9.txt /*vim9-ignored-argument* vim9-import vim9.txt /*vim9-import* +vim9-interface-type vim9.txt /*vim9-interface-type* vim9-lambda vim9.txt /*vim9-lambda* vim9-lambda-arguments vim9.txt /*vim9-lambda-arguments* vim9-line-continuation vim9.txt /*vim9-line-continuation* @@ -11618,11 +11624,14 @@ vim9-mix vim9.txt /*vim9-mix* vim9-namespace vim9.txt /*vim9-namespace* vim9-no-dict-function vim9.txt /*vim9-no-dict-function* vim9-no-shorten vim9.txt /*vim9-no-shorten* +vim9-object-type vim9.txt /*vim9-object-type* +vim9-partial-declaration vim9.txt /*vim9-partial-declaration* vim9-rationale vim9.txt /*vim9-rationale* vim9-reload vim9.txt /*vim9-reload* vim9-s-namespace vim9.txt /*vim9-s-namespace* vim9-scopes vim9.txt /*vim9-scopes* vim9-string-index vim9.txt /*vim9-string-index* +vim9-typealias-type vim9.txt /*vim9-typealias-type* vim9-types vim9.txt /*vim9-types* vim9-unpack-ignore vim9.txt /*vim9-unpack-ignore* vim9-user-command vim9.txt /*vim9-user-command* diff --git a/runtime/doc/vim9.txt b/runtime/doc/vim9.txt index 7941b83abf..6e65ca064c 100644 --- a/runtime/doc/vim9.txt +++ b/runtime/doc/vim9.txt @@ -1,4 +1,4 @@ -*vim9.txt* For Vim version 9.1. Last change: 2025 Oct 06 +*vim9.txt* For Vim version 9.1. Last change: 2025 Nov 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -24,11 +24,12 @@ features in Vim9 script. ------------------------------------------------------------------------------ NOTE: In this vim9.txt help file, the Vim9 script code blocks beginning - with `vim9script` are Vim9 script syntax highlighted. Also, they are - sourceable, meaning you can run them to see what they output. To - source them, use `:'<,'>source` (see |:source-range|), which is done - by visually selecting the line(s) with |V| and typing `:so`. - For example, try it on the following Vim9 script: >vim9 + with `vim9script` (and individual lines starting with `vim9cmd`) are + Vim9 script syntax highlighted. Also, they are sourceable, meaning + you can run them to see what they output. To source them, use + `:'<,'>source` (see |:source-range|), which is done by visually + selecting the line(s) with |V| and typing `:so`. For example, try it + on the following Vim9 script: >vim9 vim9script echowindow "Welcome to Vim9 script!" @@ -1478,38 +1479,72 @@ without arguments. Example: > ============================================================================== 4. Types *vim9-types* - *E1008* *E1009* *E1010* *E1012* - *E1013* *E1029* *E1030* -The following builtin types are supported: - bool - number - float - string - blob - list<{type}> - dict<{type}> - object<{type}> - job - channel - tuple<{type}> - tuple<{type}, {type}, ...> - tuple<...list<{type}>> - tuple<{type}, ...list<{type}>> - func - func: {type} - func({type}, ...) - func({type}, ...): {type} + +The following types, each shown with its corresponding internal |v:t_TYPE| +variable, are supported: + + number |v:t_number| + string |v:t_string| + func |v:t_func| + func: {type} |v:t_func| + func({type}, ...) |v:t_func| + func({type}, ...): {type} |v:t_func| + list<{type}> |v:t_list| + dict<{type}> |v:t_dict| + float |v:t_float| + bool |v:t_bool| + none |v:t_none| + job |v:t_job| + channel |v:t_channel| + blob |v:t_blob| + class |v:t_class| + object |v:t_object| + typealias |v:t_typealias| + enum |v:t_enum| + enumvalue |v:t_enumvalue| + tuple<{type}> |v:t_tuple| + tuple<{type}, {type}, ...> |v:t_tuple| + tuple<...list<{type}>> |v:t_tuple| + tuple<{type}, ...list<{type}>> |v:t_tuple| void -These types can be used in declarations, but no simple value will actually -have the "void" type. Trying to use a void (e.g. a function without a -return value) results in error *E1031* *E1186* . + *E1031* *E1186* +These types can be used in declarations, though no simple value can have the +"void" type. Trying to use a void as a value results in an error. Examples: >vim9 -There is no array type, use list<{type}> instead. For a list constant an -efficient implementation is used that avoids allocating a lot of small pieces -of memory. + vim9script + def NoReturnValue(): void + enddef + try + const X: any = NoReturnValue() + catch + echo v:exception # E1031: Cannot use void value + try + echo NoReturnValue() + catch + echo v:exception # E1186: Expression does not result in a ... + endtry + endtry +< *E1008* *E1009* *E1010* *E1012* +Ill-formed declarations and mismatching types result in errors. The following +are examples of errors E1008, E1009, E1010, and E1012: >vim9 + + vim9cmd var l: list + vim9cmd var l: list + vim9cmd var l: list = ['42'] +< +There is no array type. Instead, use either a list or a tuple. Those types +may also be literals (constants). In the following example, [5, 6] is a list +literal and (7, ) a tuple literal. The echoed list is a list literal too: >vim9 + + vim9script + var l: list = [1, 2] + var t: tuple<...list> = (3, 4) + echo [l, t, [5, 6], (7, )] +< *tuple-type* -A tuple type can be declared in more or less specific ways: +A tuple type may be declared in the following ways: tuple a tuple with a single item of type |Number| tuple a tuple with two items of type |Number| and |String| @@ -1535,7 +1570,9 @@ variadic tuple must end with a list type. Examples: > var myTuple: tuple<...list> = () < *vim9-func-declaration* *E1005* *E1007* -A partial and function can be declared in more or less specific ways: + *vim9-partial-declaration* + *vim9-func-type* +A function (or partial) may be declared in the following ways: func any kind of function reference, no type checking for arguments or return value func: void any number and type of arguments, no return @@ -1567,352 +1604,881 @@ If the return type is "void" the function does not return a value. The reference can also be a |Partial|, in which case it stores extra arguments and/or a dictionary, which are not visible to the caller. Since they are -called in the same way the declaration is the same. +called in the same way, the declaration is the same. This interactive example +prompts for a circle's radius and returns its area to two decimal places, +using a partial: >vim9 -Custom types can be defined with `:type`: > - :type MyList list -Custom types must start with a capital letter, to avoid name clashes with -builtin types added later, similarly to user functions. - -And classes and interfaces can be used as types: > - :class MyClass - :var mine: MyClass + vim9script + def CircleArea(pi: float, radius: float): float + return pi * radius->pow(2) + enddef + const AREA: func(float): float = CircleArea->function([3.14]) + const RADIUS: float = "Enter a radius value: "->input()->str2float() + echo $"\nThe area of a circle with a radius of {RADIUS} is " .. + $"{AREA(RADIUS)} (π to two d.p.)" +< + *vim9-typealias-type* +Custom types (|typealias|) can be defined with `:type`. They must start with +a capital letter (which avoids name clashes with either current or future +builtin types) similar to user functions. This example creates a list of +perfect squares and reports on |type()| (14, a typealias) and the |typename()|: >vim9 - :interface MyInterface - :var mine: MyInterface + vim9script + type Ln = list + final perfect_squares: Ln = [1, 4, 9, 16, 25] + echo "Typename (Ln): " .. + $"type() is {Ln->type()} and typename() is {Ln->typename()}" +< + *E1105* +A typealias itself cannot be converted to a string: >vim9 - :class MyTemplate - :var mine: MyTemplate - :var mine: MyTemplate + vim9script + type Ln = list + const FAILS: func = (): string => { + echo $"{Ln}" # E1105: Cannot convert typealias to string + } +< + *vim9-class-type* *vim9-interface-type* + *vim9-object-type* +A |class|, |object|, and |interface| may all be used as types. The following +interactive example prompts for a float value and returns the area of two +different shapes. It also reports on the |type()| and |typename()| of the +classes, objects, and interface: >vim9 - :class MyInterface - :var mine: MyInterface - :var mine: MyInterface -{not implemented yet} + vim9script + interface Shape + def InfoArea(): tuple + endinterface + class Circle implements Shape + var radius: float + def InfoArea(): tuple + return ('Circle (π × r²)', 3.141593 * this.radius->pow(2)) + enddef + endclass + class Square implements Shape + var side: float + def InfoArea(): tuple + return ('Square (s²)', this.side->pow(2)) + enddef + endclass + const INPUT: float = "Enter a float value: "->input()->str2float() + echo "\nAreas of shapes:" + var myCircle: object = Circle.new(INPUT) + var mySquare: object = Square.new(INPUT) + final shapes: list = [myCircle, mySquare] + for shape in shapes + const [N: string, A: float] = shape.InfoArea() + echo $"\t- {N} has area of {A}" + endfor + echo "\n\t\ttype()\ttypename()\n\t\t------\t----------" + echo $"Circle\t\t{Circle->type()}\t{Circle->typename()}" + echo $"Square\t\t{Square->type()}\t{Square->typename()}" + echo $"Shape\t\t{Shape->type()}\t{Shape->typename()}" + echo $"MyCircle\t{myCircle->type()}\t{myCircle->typename()}" + echo $"MySquare\t{mySquare->type()}\t{mySquare->typename()}" + echo $"shapes\t\t{shapes->type()}\t{shapes->typename()}" +< + *vim9-enum-type* *vim9-enumvalue-type* +An |enum| may be used as a type (|v:t_enum|). Variables holding enum values +have the enumvalue type (|v:t_enumvalue|) at runtime. The following +interactive example prompts for a character and returns information about +either a square or a rhombus. It also reports on the |type()| and |typename()| +of the enum and enumvalue: >vim9 + vim9script + enum Quad + Square('four', 'only'), + Rhombus('opposite', 'no') + var eq: string + var ra: string + def string(): string + return $"\nA {this.name} has " .. + $"{this.eq} equal sides and {this.ra} right angles\n\n" + enddef + endenum + echo "Rhombus (r) or Square (s)?" + var myQuad: Quad = getcharstr() =~ '\c^R' ? Quad.Rhombus : Quad.Square + echo myQuad.string() .. "\ttype()\ttypename()" + echo $"Quad \t{Quad->type()} \t{Quad->typename()}" + echo $"myQuad\t{myQuad->type()}\t{myQuad->typename()}" +< + Notes: This script uses builtin method "string()" (|object-string()|). + The typename() of Quad and myQuad are the same ("enum") + whereas the type() is distinguished (myQuad returns 16, + enumvalue, whereas Quad returns 15, enum). Variable types and type casting ~ *variable-types* Variables declared in Vim9 script or in a `:def` function have a type, either specified explicitly or inferred from the initialization. -Global, buffer, window and tab page variables do not have a specific type, the -value can be changed at any time, possibly changing the type. Therefore, in -compiled code the "any" type is assumed. - -This can be a problem when the "any" type is undesired and the actual type is -expected to always be the same. For example, when declaring a list: > - var l: list = [1, g:two] -At compile time Vim doesn't know the type of "g:two" and the expression type -becomes list. An instruction is generated to check the list type before -doing the assignment, which is a bit inefficient. - *type-casting* *E1104* -To avoid this, use a type cast: > - var l: list = [1, g:two] -The compiled code will then only check that "g:two" is a number and give an -error if it isn't. This is called type casting. - -The syntax of a type cast is: "<" {type} ">". There cannot be white space -after the "<" or before the ">" (to avoid them being confused with -smaller-than and bigger-than operators). - -The semantics is that, if needed, a runtime type check is performed. The -value is not actually changed. If you need to change the type, e.g. to change -it to a string, use the |string()| function. Or use |str2nr()| to convert a +Global, buffer, window and tab page variables do not have a specific type. +Consequently, their values may change at any time, possibly changing the type. +Therefore, in compiled code, the "any" type is assumed. + +This can be a problem when stricter typing is desired, for example, when +declaring a list: > + var l: list = [1, b:two] +Since Vim doesn't know the type of "b:two", the expression becomes list. +A runtime check verifies the list matches the declared type before assignment. + + *type-casting* +To get more specific type checking, use type casting. This checks the +variable's type before building the list, rather than checking whether +list items match the declared type. For example: > + var l: list = [1, b:two] +< +So, here the type cast checks whether "b:two" is a number and gives an error +if it isn't. + +The difference is demonstrated in the following example. With funcref +variable "NTC", Vim infers the expression type "[1, b:two]" as list, then +verifies whether it can be assigned to the list return type. With +funcref variable "TC", the type cast means Vim first checks whether "b:two" is +a type: >vim9 + + vim9script + b:two = '2' + const NTC: func = (): list => { + return [1, b:two] + } + disassemble NTC # 3 CHECKTYPE list stack [-1] + try + NTC() + catch + echo v:exception .. "\n\n" # expected list but... + endtry + const TC: func = (): list => { + return [1, b:two] + } + disassemble TC # 2 CHECKTYPE number stack [-1] + try + TC() + catch + echo v:exception # expected number but got string + endtry +< + Note: Notice how the error messages differ, showing when + type checking occurs. + + *E1104* +The syntax of a type cast is "<{type}>". An error occurs if either the +opening "<" (|E121|) or closing ">" (E1104) is omitted. Also, white space +is not allowed either after the "<" (|E15|) or before the ">" (|E1068|), which +avoids ambiguity with smaller-than and greater-than operators. + +Although a type casting forces explicit type checking, it neither changes the +value of, nor the type of, a variable. If you need to alter the type, use a +function such as |string()| to convert to a string, or |str2nr()| to convert a string to a number. -If a type is given where it is not expected you can get *E1272* . +If type casting is applied to a chained expression, it must be compatible with +the final result. Examples: >vim9 + + vim9script + # These type casts work + echo >[3, 2, 1]->extend(['Go!']) + echo [3, 2, 1]->extend(['Go!'])->string() + echo >>[3, 2, 1]->list2tuple() + # This type cast fails + echo [3, 2, 1]->extend(['Go!'])->string() +< + *E1272* +If a type is used in a context where types are not expected you can get +E1272. For example: > + :vim9cmd echo islocked('x: string') +< Note: This must be executed from Vim's command line, not sourced. -If a type is incomplete you get *E1363* , e.g. when you have an object for -which the class is not known (usually that is a null object). + *E1363* +If a type is incomplete, such as when an object's class is unknown, E1363 +results. For example: >vim9 + + vim9script + var E1363 = null_class.member # E1363: Incomplete type +< +Another null object-related error is |E1360|: >vim9 + + vim9script + var obj = null_object + var E1360 = obj.MyMethod() # E1360: Using a null object +< Type inference ~ *type-inference* -In general: Whenever the type is clear it can be omitted. For example, when -declaring a variable and giving it a value: > - var name = 0 # infers number type - var name = 'hello' # infers string type - -The type of a list and dictionary comes from the common type of the values. -If the values all have the same type, that type is used for the list or -dictionary. If there is a mix of types, the "any" type is used. > - [1, 2, 3] list - ['a', 'b', 'c'] list - [1, 'x', 3] list - -The common type of function references, if they do not all have the same -number of arguments, uses "(...)" to indicate the number of arguments is not -specified. For example: > - def Foo(x: bool) +Declaring types explicitly provides many benefits, including targeted type +checking and clearer error messages. Nonetheless, Vim often can infer types +automatically when they are omitted. For example, each of these variables' +types are inferred, with the |type()| and |typename()| echoed showing those +inferred types: >vim9 + + vim9script + echo "\t type()\t typename()" + var b = true | echo $"{b} \t {b->type()} \t {b->typename()}" + var f = 4.2 | echo $"{f} \t {f->type()} \t {f->typename()}" + var l = [1, 2] | echo $"{l} \t {l->type()} \t {l->typename()}" + var n = 42 | echo $"{n} \t {n->type()} \t {n->typename()}" + var s = 'yes' | echo $"{s} \t {s->type()} \t {s->typename()}" + var t = (42, ) | echo $"{t} \t {t->type()} \t {t->typename()}" +< +The type of a list, tuple, or dictionary is inferred from the common type of +its values. When the values are all the same type, that type is used. +If there is a mix of types, the "any" type is used. In the following example, +the echoed |typename()| for each literal demonstrates these points: >vim9 + + vim9script + echo [1, 2]->typename() # list + echo [1, 'x']->typename() # list + echo {ints: [1, 2], bools: [false]}->typename() # dict> + echo (true, false)->typename() # tuple +< +The common type of function references, when they do not all have the same +number of arguments, is indicated with "(...)", meaning the number of +arguments is unequal. This script demonstrates a "list": >vim9 + + vim9script + def Foo(x: bool): void enddef - def Bar(x: bool, y: bool) + def Bar(x: bool, y: bool): void enddef var funclist = [Foo, Bar] echo funclist->typename() -Results in: - list +< +Script-local variables in a Vim9 script are type checked. The type is +also checked for variables declared in a legacy function. For example: >vim9 -For script-local variables in Vim9 script the type is checked, also when the -variable was declared in a legacy function. + vim9script + var my_local = (1, 2) + function Legacy() + let b:legacy = [1, 2] + endfunction + Legacy() + echo $"{my_local} is type {my_local->type()} ({my_local->typename()})" + echo $"{b:legacy} is type {b:legacy->type()} ({b:legacy->typename()})" +< + *E1013* +When a type is declared for a List, Tuple, or Dictionary, the type is attached +to it. Similarly, if a type is not declared, the type Vim infers is attached. +In either case, if an expression attempts to change the type, E1013 results. +This example has its type inferred and demonstrates E1013: >vim9 -When a type has been declared this is attached to a List or Dictionary. When -later some expression attempts to change the type an error will be given: > - var ll: list = [1, 2, 3] - ll->extend(['x']) # Error, 'x' is not a number + vim9script + var lb = [true, true] # Two bools, so Vim infers list type + echo lb->typename() # Echoes list + lb->extend([0]) # E1013 Argument 2: type mismatch, ... +< +If you want a permissive list, either explicitly use or declare an +empty list initially (or both, i.e., `list = []`). Examples: >vim9 -If the type is not declared then it is allowed to change: > - [1, 2, 3]->extend(['x']) # result: [1, 2, 3, 'x'] + vim9script + final la: list = [] + echo la->extend(['two', 1]) + final le = [] + echo le->extend(la) +< +Similarly for a permissive dictionary: >vim9 -For a variable declaration an inferred type matters: > - var ll = [1, 2, 3] - ll->extend(['x']) # Error, 'x' is not a number -That is because the declaration looks like a list of numbers, thus is -equivalent to: > - var ll: list = [1, 2, 3] -If you do want a more permissive list you need to declare the type: > - var ll: list = [1, 2, 3] - ll->extend(['x']) # OK + vim9script + final da: dict = {} + echo da->extend({2: 2, 1: 'One'}) + final de = {} + echo de->extend(da)->string() +< +And, although tuples themselves are immutable, permissive tuple concatenation +can be achieved with either "any" or an empty tuple: >vim9 + vim9script + var t_any: tuple<...list> = (3, '2') + t_any = t_any + (true, ) + echo t_any + var t_dec_empty = () + t_dec_empty = t_dec_empty + (3, '2', true) + echo t_dec_empty +< +If a list literal or dictionary literal is not bound to a variable, its type +may change, as this example shows: >vim9 + + vim9script + echo [3, 2, 1]->typename() # list + echo [3, 2, 1]->extend(['Zero'])->typename() # list + echo {1: ['One']}->typename() # dict> + echo {1: ['One']}->extend({2: [2]})->typename() # dict> +< Stricter type checking ~ - *type-checking* + *type-checking* In legacy Vim script, where a number was expected, a string would be automatically converted to a number. This was convenient for an actual number such as "123", but leads to unexpected problems (and no error message) if the string doesn't start with a number. Quite often this leads to hard-to-find -bugs. e.g.: > +bugs. For example, in legacy Vim script this echoes "1": >vim + echo 123 == '123' -< 1 ~ -With an accidental space: > +< +However, if an unintended space is included, "0" is echoed: >vim + echo 123 == ' 123' -< 0 ~ - *E1206* *E1210* *E1212* +< + *E1206* In Vim9 script this has been made stricter. In most places it works just as -before if the value used matches the expected type. There will sometimes be -an error, thus breaking backwards compatibility. For example: -- Using a number other than 0 or 1 where a boolean is expected. *E1023* -- Using a string value when setting a number option. -- Using a number where a string is expected. *E1024* *E1105* +before if the value used matches the expected type. For example, in both +legacy Vim script and Vim9 script trying to use anything other than a +dictionary when it is required: >vim + + echo [8, 9]->keys() + vim9cmd echo [8, 9]->keys() # E1206: Dictionary required +< + *E1023* *E1024* *E1029* + *E1030* *E1210* *E1212* +However, sometimes there will be an error in Vim9 script, which breaks +backwards compatibility. The following examples illustrate various places +this happens. The legacy Vim script behavior, which does not fail, is shown +first. It is followed by the error that occurs if the same command is used +in Vim9 script. + + - Using a number (except 0 or 1) where a bool is expected: >vim + + echo v:version ? v:true : v:false + vim9cmd echo v:version ? true : false # E1023: Using a Number as a... +< + - Using a number where a string is expected: >vim + + echo filter([1, 2], 0) + vim9cmd echo filter([1, 2], 0) # E1024: Using a Number as a String +< + - Not using a number where a number is expected: >vim + + " In this example, Vim script treats v:false as 0 + function Not1029() + let b:l = [42] | unlet b:l[v:false] + endfunction + call Not1029() | echo b:l +< >vim9 + vim9script + def E1029(): void + b:l = [42] | unlet b:l[false] + enddef + E1029() # E1029: Expected number but got bool +< + - Using a string as a number: >vim + let b:l = [42] | unlet b:l['#'] | echo b:l + vim9cmd b:l = [42] | vim9cmd unlet b:l['#'] # E1030: Using a string... +< + - Not using a number when it is required: >vim + + echo gettabinfo('a') + vim9cmd echo gettabinfo('a') # E1210: Number required for argument 1 +< + - Not using a bool when it is required: >vim + + echo char2nr('¡', 2) + vim9cmd echo char2nr('¡', 2) # E1212: Bool required for argument 2 +< + - Not using a number when a number is required (|E521|): >vim + + let &laststatus='2' + vim9cmd &laststatus = '2' +< + - Not using a string when a string is required (|E928|): >vim + + let &langmenu = 42 + vim9cmd &langmenu = 42 # E928: String required +< + - Comparing a |Special| with 'is' fails in some instances (|E1037|, |E1072|): >vim + + " 1 is echoed because these are both true + echo v:null is v:null && v:none is v:none + " 0 is echoed because all these expressions are false + echo v:none is v:null || v:none is 8 || v:true is v:none + " All these are errors in Vim9 script + vim9cmd echo v:null is v:null # E1037: Cannot use 'is' with special + vim9cmd echo v:none is v:none # E1037: Cannot use 'is' with special + vim9cmd echo v:none is v:null # E1037: Cannot use 'is' with special + vim9cmd echo v:none is 8 # E1072: Cannot compare special with numb + vim9cmd echo v:true is v:none # E1072: Cannot compare bool with special +< + Note: Although the last two Vim9 script examples above error using + `v:none`, they return `false` using `null` (which is the same + as `v:null` - see |v:null|): >vim9 + + vim9script + echo null is 8 # false + echo true is null # false +< + - Using a string where a bool is required (|E1135|): >vim + + echo '42' ? v:true : v:false + vim9cmd echo '42' ? true : false # E1135: Using a String as a Bool +< + - Using a bool as a number (|E1138|): >vim + + let &laststatus=v:true + vim9cmd &laststatus = true +< + - Not using a string where an argument requires a string (|E1174|) >vim + + echo substitute('Hallo', 'a', 'e', v:true) + vim9cmd echo substitute('Hallo', 'a', 'e', true) # E1174: String... +< One consequence is that the item type of a list or dict given to |map()| must -not change, if the type was declared. This will give an error in Vim9 -script: > - var mylist: list = [1, 2, 3] - echo map(mylist, (i, v) => 'item ' .. i) -< E1012: Type mismatch; expected number but got string in map() ~ - -Instead use |mapnew()|, it creates a new list: > - var mylist: list = [1, 2, 3] - echo mapnew(mylist, (i, v) => 'item ' .. i) -< ['item 0', 'item 1', 'item 2'] ~ - -If the item type was not declared or determined to be "any" it can change to a -more specific type. E.g. when a list of mixed types gets changed to a list of -strings: > - var mylist = [1, 2.0, '3'] - # typename(mylist) == "list" - map(mylist, (i, v) => 'item ' .. i) - # typename(mylist) == "list", no error - -There is a subtle difference between using a list constant directly and -through a variable declaration. Because of type inference, when using a list -constant to initialize a variable, this also sets the declared type: > - var mylist = [1, 2, 3] - # typename(mylist) == "list" - echo map(mylist, (i, v) => 'item ' .. i) # Error! - -When using the list constant directly, the type is not declared and is allowed -to change: > - echo map([1, 2, 3], (i, v) => 'item ' .. i) # OK - -The reasoning behind this is that when a type is declared and the list is -passed around and changed, the declaration must always hold. So that you can -rely on the type to match the declared type. For a constant this is not -needed. - - *E1158* -Same for |extend()|, use |extendnew()| instead, and for |flatten()|, use -|flattennew()| instead. Since |flatten()| is intended to always change the -type, it can not be used in Vim9 script. +not change when its type is either declared or inferred. For example, this +gives an error in Vim9 script, whereas in legacy Vim script it is allowed: >vim + + " legacy Vim script changes s:mylist to ['item 0', 'item 1'] + let s:mylist = [0, 1] + call map(s:mylist, {i -> $"item {i}"}) + echo s:mylist +< >vim9 + vim9script + var mylist = [0, 1] # Vim infers mylist is list + map(mylist, (i, _) => $"item {i}") # E1012: type mismatch... +< +The error occurs because `map()` tries to modify the list elements to strings, +which conflicts with the declared type. + +Use |mapnew()| instead. It creates a new list, and Vim infers its type if it +is not specified. Inferred and declared types are shown in this example: >vim9 + + vim9script + var mylist = [0, 1] + var infer = mylist->mapnew((i, _) => $"item {i}") + echo [infer, infer->typename()] + var declare: list = mylist->mapnew((i, _) => $"item {i}") + echo [declare, declare->typename()] +< +The key concept here is, variables with declared or inferred types cannot +have the types of the elements within their containers change. However, type +"changes" are allowed for either: + - a container literal (not bound to a variable), or + - a container where |copy()| or |deepcopy()| is used in method chaining. +Both are demonstrated in this example: >vim9 + + vim9script + # list literal + echo [1, 2]->map((_, v) => $"#{v}") + echo [1, 2]->map((_, v) => $"#{v}")->typename() + # deepcopy() in a method chain + var mylist = [1, 2] + echo mylist->deepcopy()->map((_, v) => $"#{v}") + echo mylist->deepcopy()->map((_, v) => $"#{v}")->typename() + echo mylist +< +The reasoning behind this is, when a type is either declared or inferred +and the list is passed around and changed, the declaration/inference must +always hold so that you can rely on the type to match the declared/inferred +type. For either a list literal or a fully copied list, that type safety is +not needed because the original list is unchanged (as "echo mylist" shows, +above). + +If the item type was not declared or determined to be "", it will not +change, even if all items later become the same type. However, when `mapnew()` +is used, inference means that the new list will reflect the type(s) present. +For example: >vim9 + + vim9script + # list + var mylist = [1, '2'] # mixed types, i.e., list + echo (mylist, mylist->typename()) # ([1, '2'], 'list') + mylist->map((_, v) => $"item {v}") # all items are now strings + echo (mylist, mylist->typename()) # both strings, but list + # mapnew() + var newlist = mylist->mapnew((_, v) => v) + echo (newlist, newlist->typename()) # newlist is a list +< +Using |extend()| and |extendnew()| is similar, i.e., a list literal may use +the former, so, this is okay: >vim9 + + vim9cmd echo [1, 2]->extend(['3']) # [1, 2, 3] +< +whereas, this is not: >vim9 + vim9script + var mylist: list = [1, 2] + echo mylist->extend(['3']) # E1013: Argument 2: type mismatch +< +Using |extendnew()| is needed for extending an existing typed list, except +where the extension matches the list's type (or it is "any"). For example, +first extending with an element of the same type, then extending with a +different type: >vim9 + + vim9script + var mylist: list = [1, 2] + mylist->extend([3]) + echo mylist->extendnew(['4']) # [1, 2, 3, '4'] + +< *E1158* +Using |flatten()| is not allowed in Vim9 script, because it is intended +always to change the type. This even applies to a list literal +(unlike |map()| and |extend()|). Instead, use |flattennew()|: >vim9 + + vim9cmd [1, [2, 3]]->flatten() # E1158: Cannot use flatten + vim9cmd echo [1, [2, 3]]->flattennew() # [1, 2, 3] +< Assigning to a funcref with specified arguments (see |vim9-func-declaration|) -does strict type checking of the arguments. For variable number of arguments -the type must match: > - var FuncRef: func(string, number, bool): number - FuncRef = (v1: string, v2: number, v3: bool) => 777 # OK - FuncRef = (v1: string, v2: number, v3: number) => 777 # Error! - # variable number of arguments must have same type - var FuncVA: func(...list): number - FuncVA = (...v: list): number => v # Error! - FuncVA = (...v: list): number => v # OK, `any` runtime check - FuncVA = (v1: string, v: string2): number => 333 # Error! - FuncVA = (v: list): number => 3 # Error! - -If the destination funcref has no specified arguments, then there is no -argument type checking: > - var FuncUnknownArgs: func: number - FuncUnknownArgs = (v): number => v # OK - FuncUnknownArgs = (v1: string, v2: string): number => 3 # OK - FuncUnknownArgs = (...v1: list): number => 333 # OK -< - *E1211* *E1217* *E1218* *E1219* *E1220* *E1221* - *E1222* *E1223* *E1224* *E1225* *E1226* *E1227* - *E1228* *E1235* *E1238* *E1250* *E1251* *E1252* - *E1253* *E1256* *E1297* *E1298* *E1301* *E1528* - *E1529* *E1530* *E1531* *E1534* +involves strict type checking of the arguments. For example, this works: >vim9 + + vim9script + var F_name_age: func(string, number): string + F_name_age = (n: string, a: number): string => $"Name: {n}, Age: {a}" + echo F_name_age('Bob', 42) +< +whereas this fails with error |E1012| (type mismatch): >vim9 + + vim9script + var F_name_age: func(string, number): string + F_name_age = (n: string, a: string): string => $"Name: {n}, Age: {a}" +< +If there is a variable number of arguments they must have the same type, as in +this example: >vim9 + + vim9script + var Fproduct: func(...list): number + Fproduct = (...v: list): number => reduce(v, (a, b) => a * b) + echo Fproduct(3, 2, 4) # Echoes 24 +< +And may be used to accommodate mixed types: >vim9 + + vim9script + var FlatSort: func(...list): any + FlatSort = (...v: list) => flattennew(v)->sort('n') + echo FlatSort(true, [[[5, 3], 2], 4]) # Echoes [true, 2, 3, 4, 5] +< + Note: Using in a lambda does not avoid type checking of the + funcref. It remains constrained by the declared funcref's + type and, as these examples show, a runtime or compiling error + occurs when the types mismatch: >vim9 + + vim9script + var FuncSN: func(string): number + FuncSN = (v: any): number => v->str2nr() + echo FuncSN('162')->nr2char() # Echoes ¢ + echo FuncSN(162)->nr2char()) # E1013 (runtime error) +< >vim9 + vim9script + var FuncSN: func(string): number + FuncSN = (v: any): number => v->str2nr() + def FuncSNfail(): void + echo FuncSN('162')->nr2char() # No echo because ... + echo FuncSN(162)->nr2char() # Error while compiling + enddef + FuncSNfail() +< +When the funcref has no arguments specified, there is no type checking. This +example shows FlexArgs has a string argument the first time and a list the +following time: >vim9 + + vim9script + var FlexArgs: func: string + FlexArgs = (s: string): string => $"It's countdown time {s}..." + echo FlexArgs("everyone") + FlexArgs = (...values: list): string => join(values, ', ') + echo FlexArgs('3', '2', '1', 'GO!') +< + *E1211* *E1217* *E1218* *E1219* *E1220* *E1221* *E1222* + *E1223* *E1224* *E1225* *E1226* *E1228* *E1235* *E1238* + *E1251* *E1253* *E1256* *E1297* *E1298* *E1301* *E1528* + *E1529* *E1530* *E1531* *E1534* Types are checked for most builtin functions to make it easier to spot -mistakes. +mistakes. The following one-line |:vim9| commands, calling builtin functions, +demonstrate many of those type-checking errors: >vim9 + + vim9 9->list2blob() # E1211: List required for argument 1 + vim9 9->ch_close() # E1217: Channel or Job required for + vim9 9->job_info() # E1218: Job required for argument 1 + vim9 [9]->cos() # E1219: Float or Number required for + vim9 {}->remove([]) # E1220: String or Number required + vim9 null_channel->ch_evalraw(9) # E1221: String or Blob required for + vim9 9->col() # E1222: String or List required for + vim9 9->complete_add() # E1223: String or Dictionary require + vim9 setbufline(9, 9, {}) # E1224: String, Number or List + vim9 9->count(9) # E1225: String, List, Tuple or Dict + vim9 9->add(9) # E1226: List or Blob required for + vim9 9->remove(9) # E1228: List, Dictionary, or Blob + vim9 getcharstr('9') # E1235: Bool or number required for + vim9 9->blob2list() # E1238: Blob required for argument 1 + vim9 9->filter(9) # E1251: List, Tuple, Dictionary, Blo + vim9 9->reverse() # E1253: String, List, Tuple or Blob + vim9 9->call(9) # E1256: String or Function required + vim9 null_dict->winrestview() # E1297: Non-NULL Dictionary required + vim9 {}->prop_add_list(null_list) # E1298: Non-NULL List required for + vim9 {}->repeat(9) # E1301: String, Number, List, Tuple + vim9 9->index(9) # E1528: List or Tuple or Blob + vim9 9->join() # E1529: List or Tuple required for + vim9 9->max() # E1530: List or Tuple or Dictionary + vim9 9->get(9) # E1531: Argument of get() must be a + vim9 9->tuple2list() # E1534: Tuple required for argument +< +Reserved for future use: *E1227* *E1250* *E1252* + E1227: List or Dictionary required for argument %d + E1250: Argument of %s must be a List, String, Dictionary or Blob + E1252: String, List or Blob required for argument %d + Categories of variables, defaults and null handling ~ - *variable-categories* *null-variables* -There are categories of variables: + *variable-categories* *null-variables* +There are three categories of variables: primitive number, float, boolean container string, blob, list, tuple, dict specialized function, job, channel, user-defined-object When declaring a variable without an initializer, an explicit type must be -provided. Each category has different default initialization semantics. Here's -an example for each category: > - var num: number # primitives default to a 0 equivalent - var cont: list # containers default to an empty container - var spec: job # specialized variables default to null -< -Vim does not have a familiar null value; it has various null_ predefined -values, for example |null_string|, |null_list|, |null_job|. Primitives do not -have a null_. The typical use cases for null_ are: -- to clear a variable and release its resources; -- as a default for a parameter in a function definition, see |null-compare|. +provided. Each category has different default initialization semantics. + +Primitives default to type-specific values. All primitives are empty but do +not equal `null`: >vim9 + + vim9script + var n: number | echo [n, n->empty(), n == null] # [0, 1, false] + var f: float | echo [f, f->empty(), f == null] # [0.0, 1, false] + var b: bool | echo [b, b->empty(), b == null] # [false, 1, false] +< +Containers default to an empty container. Only an empty string equals `null`: >vim9 + + vim9script + var s: string | echo [s, s->empty(), s == null] # ['', 1, true] + var z: blob | echo [z, z->empty(), z == null] # [0z, 1, false] + var l: list | echo [l, l->empty(), l == null] # [[], 1, false] + var t: tuple | echo [t, t->empty(), t == null] # [(), 1, false] + var d: dict | echo [d, d->empty(), d == null] # [{}, 1, false] +< +Specialized types default to equaling `null`: >vim9 + + vim9script + var F: func | echo [F, F == null] # [function(''), true] + var j: job | echo [j, j == null] # ['no process', true] + var c: channel | echo [c, c == null] # ['channel fail', true] + class Class + endclass + var o: Class | echo [o, o == null] # [object of [unknown], true] + enum Enum + endenum + var e: Enum | echo [e, e == null] # [object of [unknown], true] +< + Note: See |empty()| for explanations of empty job, empty channel, and + empty object types. + +Vim does not have a familiar null value. Instead, it has various null_ +predefined values including |null_string|, |null_list|, and |null_job|. +Primitives do not have a null_. Typical use cases for null_ are: + - to clear a variable and release its resources, + - as a default for a parameter in a function definition (for an example, + see |null_blob|), or + - assigned to a container or specialized variable to set it to null + for later comparison (for an example, see |null-compare|). For a specialized variable, like `job`, null_ is used to clear the -resources. For a container variable, resources can also be cleared by -assigning an empty container to the variable. For example: > - var j: job = job_start(...) - # ... job does its work - j = null_job # clear the variable and release the job's resources - - var l: list - # ... add lots of stuff to list - l = [] # clear the variable and release container resources -Using the empty container, rather than null_, to clear a container -variable may avoid null complications as described in |null-anomalies|. +resources. For example: >vim9 + + vim9script + var mydate: list + def Date(channel: channel, msg: string): void + mydate->add(msg) + enddef + var myjob = job_start([&shell, &shellcmdflag, 'date'], {out_cb: Date}) + echo [myjob, myjob->job_status()] + sleep 2 + echo $"The date and time is {mydate->join('')}" + echo [myjob, myjob->job_status()] + myjob = null_job # Clear the variable; release the job's resources. + echo myjob +< +For a container variable, resources may also be cleared by assigning an +empty container to the variable. For example: >vim9 + + vim9script + var perfect: list = [1, 4] + perfect->extend([9, 16, 25]) + perfect = [] + echo perfect + +Using an empty container, rather than null_, to clear a container +variable may avoid null complications - see |null-anomalies|. The initialization semantics of container variables and specialized variables -differ. An uninitialized container defaults to an empty container: > - var l1: list # empty container - var l2: list = [] # empty container - var l3: list = null_list # null container -"l1" and "l2" are equivalent and indistinguishable initializations; but "l3" -is a null container. A null container is similar to, but different from, an -empty container, see |null-anomalies|. - -Specialized variables default to null. These job initializations are -equivalent and indistinguishable: > +differ. For containers: + - An uninitialized container defaults to empty but does not equal `null` + (except for a uninitialized string). + - A container initialized to [], (), {}, "", or 0z is empty but does not + equal `null`. + - A container initialized as null_ defaults to empty and equals `null`. + +In the following example, the uninitialized list ("lu") and [] initialized +list ("li") are equivalent and indistinguishable whereas "ln" is a null +container, which is similar to, but not equivalent to, an empty container +(see |null-anomalies|). >vim9 + + vim9script + # uninitialized: empty container, not null + var lu: list + echo ['lu', $"empty={lu->empty()}", $"null={lu == null}"] + # initialized: empty container, not null + var li: list = [] + echo ['li', $"empty={li->empty()}", $"null={li == null}"] + # initialized: empty container, null + var ln: list = null_list + echo ['ln', $"empty={ln->empty()}", $"null={ln == null}"] +< +Specialized variables default to equaling null. These job initializations +are equivalent and indistinguishable: >vim9 + + vim9script var j1: job var j2: job = null_job var j3 = null_job + echo (j1 == j2) == (j2 == j3) # true (equivalent, indistinguishable) +< +When a list, tuple, or dict is declared, if the item type is not specified +it cannot be inferred. Consequently, the item type defaults to "any": >vim9 -When a list or dict is declared, if the item type is not specified and can not -be inferred, then the type is "any": > - var d1 = {} # type is "dict" - var d2 = null_dict # type is "dict" - -Declaring a function, see |vim9-func-declaration|, is particularly unique. + vim9script + var [t1, t2] = [(), null_tuple] + echo $'t1 is {t1->typename()} and t2 is {t2->typename()} too' +< +Tuples and functions (or partials) may be declared in various ways. +See |tuple-type|, |variadic-tuple|, and |vim9-func-declaration|. *null-compare* -For familiar null compare semantics, where a null container is not equal to -an empty container, do not use null_ in a comparison: > - vim9script - def F(arg: list = null_list) - if arg == null - echo "null" - else - echo printf("not null, %sempty", empty(arg) ? '' : 'not ') - endif +For familiar null compare semantics, where an empty container is not equal to +a null container, do not use null_ in a comparison. That is because, +in Vim9 script, although null_ == `null`, comparing an: + + - empty container to `null` is `false`, but + - empty container to null_ is `true`. + +So, compare against `null`, not null_. For example: >vim9 + + vim9script + var bonds: dict> = {g: ['007', '008'], o: ['007', '009']} + def Search(query: string): list + return query == "\r" ? null_list : bonds->get(query, []) enddef - F() # output: "null" - F(null_list) # output: "null" - F([]) # output: "not null, empty" - F(['']) # output: "not null, not empty" -The above function takes a list of strings and reports on it. -Change the above function signature to accept different types of arguments: > - def F(arg: list = null_list) # any type of list - def F(arg: any = null) # any type -< -In the above example, where the goal is to distinguish a null list from an -empty list, comparing against `null` instead of `null_list` is the correct -choice. The basic reason is because "null_list == null" and "[] != null". -Comparing to `null_list` fails since "[] == null_list". In the following section -there are details about comparison results. + echo "Goldfinger (g) or Octopussy (o)?: " + const C: string = getcharstr() + var result: list = C->Search() + if result == null # <<< DO NOT USE null_list HERE! + echo "Error: Nothing was entered" + else + echo result->empty() ? $"No matches for '{C}'" : $"{result}" + endif +< + NOTE: Using "result == null_list" instead of "result == null" would + fail to distinguish the error (nothing entered) and the valid + (nothing matched) result because [] == null_list whereas + [] != null. + +Conceptually, think of the null_ construct as a hybrid/bridge between +the general `null` and typed `empty` containers, having properties of both. +In the following section there are details about comparison results. *null-details* *null-anomalies* This section describes issues about using null and null_; included below -are the enumerated results of null comparisons. In some cases, if familiar -with vim9 null semantics, the programmer may chose to use null_ in +are the enumerated results of null comparisons. In some cases, if familiar +with vim9 null semantics, the programmer may choose to use null_ in comparisons and/or other situations. -Elsewhere in the documentation it says: - Quite often a null value is handled the same as an empty value, but - not always -Here's an example: > - vim9script - var s1: list - var s2: list = null_list - echo s1 # output: "[]" - echo s2 # output: "[]" - - echo s1 + ['a'] # output: "['a']" - echo s2 + ['a'] # output: "['a']" - - echo s1->add('a') # output: "['a']" - echo s2->add('a') # E1130: Can not add to null list -< -Two values equal to a null_ are not necessarily equal to each other: > - vim9script - echo {} == null_dict # true - echo null_dict == null # true - echo {} == null # false -< -Unlike the other containers, an uninitialized string is equal to null. The -'is' operator can be used to determine if it is a null_string: > - vim9script - var s1: string - var s2 = null_string - echo s1 == null # true - this is unexpected - echo s2 == null # true - echo s2 is null_string # true - - var b1: blob - var b2 = null_blob - echo b1 == null # false - echo b2 == null # true -< -Any variable initialized to the null_ is equal to the null_ and is -also equal to null. For example: > - vim9script - var x = null_blob - echo x == null_blob # true - echo x == null # true -< -An uninitialized variable is usually equal to null; it depends on its type: - var s: string s == null - var b: blob b != null *** - var l: list l != null *** - var t: tuple t != null *** - var d: dict d != null *** - var f: func f == null - var j: job j == null - var c: channel c == null - var o: Class o == null - -A variable initialized to empty equals null_; but not null: - var s2: string = "" == null_string != null - var b2: blob = 0z == null_blob != null - var l2: list = [] == null_list != null - var t2: tuple = () == null_tuple != null - var d2: dict = {} == null_dict != null - -NOTE: the specialized variables, like job, default to null value and have no -corresponding empty value. +Elsewhere in the documentation it says, "often a null value is handled the +same as an empty value, but not always". For example, you cannot add to a +null container: >vim9 + + vim9script + var le: list = [] + le->add('Okay') # le is now ['Okay'] + var ln = null_list + ln->add("E1130") # E1130: Cannot add to null list +< +As explained in |null-compare|, there is a non-transitive relationship among +`null`, null_ containers, and `empty`. To recap, for example: >vim9 + + vim9cmd echo (null_dict == {}, null_dict == null, {} != null) +< +The exception is an uninitialized string. It is equal to `null` (and is the +same instance as `null_string`). The 'is' operator (|expr-is|) may be used to +determine whether a string is uninitialized: >vim9 + + vim9script + var s: string + echo s == null_string # true + echo s is null_string # true (the same instance) + echo s == null # true (unexpected, perhaps) + echo s is null # false (not the same instance) +< +However, don't do the same for the other containers because, when evaluated +against their applicable null_ with 'is', they return `false`: >vim9 + + vim9script + var d: dict + echo d == null_dict # true + echo d is null_dict # false (not the same instance) + echo d == null # false (as expected) + echo d is null # false (not the same instance) +< +The key distinction here is an uninitialized string is implemented as +`null_string`, while an uninitialized list, dict, tuple, or blob is +implemented as an empty container ([], {}, (), and 0z respectively). +So, those uninitialized types are equal to, but not the same instance as, +their null_ counterparts, as this example shows: >vim9 + + vim9script + var t: tuple + echo t == null_tuple # true + echo t is null_tuple # false + +However, a variable initialized to the null_ is equal not only to the +null_, it is also equal to null. For example: >vim9 + + vim9script + var t: tuple = null_tuple + echo t == null_tuple # true + echo t is null_tuple # true + echo t == null # true +< +An uninitialized container variable is not equal to null, except for an +uninitialized string, which is explained in an example, above. So, these +all echo `true`: >vim9 + + vim9script + var b: blob | echo b != null + var d: dict | echo d != null + var l: list | echo l != null + var t: tuple | echo t != null + var s: string | echo s == null + +An uninitialized specialized variable is equal to null so these all echo `true`: >vim9 + + vim9script + var c: channel | echo c == null + var F: func | echo F == null + var j: job | echo j == null + class Class + endclass + var nc: Class | echo nc == null + enum Enum + endenum + var ne: Enum | echo ne == null +< + Note: the specialized variables, like job, default to null and + no specialized variable has a corresponding empty value. + +A container variable initialized to empty equals null_, so these are all +`true`: >vim9 + + vim9script + var s: string = "" | echo s == null_string + var b: blob = 0z | echo b == null_blob + var l: list = [] | echo l == null_list + var t: tuple = () | echo t == null_tuple + var d: dict = {} | echo d == null_dict +< +However, a container variable initialized to empty does not equal null, so +these are all `true`: >vim9 + + vim9script + var s: string = "" | echo s != null + var b: blob = 0z | echo b != null + var l: list = [] | echo l != null + var t: tuple = () | echo t != null + var d: dict = {} | echo d != null +< ============================================================================== @@ -1972,13 +2538,13 @@ errors: >vim9 vim9script My1558() - # Vim(eval):E1558: Unknown generic function: My1558 + # E1558: Unknown generic function: My1558 < >vim9 vim9script def My1560(): void enddef My1560() - # Vim(echo):E1560: Not a generic function: My1560 + # E1560: Not a generic function: My1560 < *E1561* Type parameter names must not clash with other identifiers: >vim9 diff --git a/runtime/doc/vim9class.txt b/runtime/doc/vim9class.txt index 0991c1b77a..3d58184224 100644 --- a/runtime/doc/vim9class.txt +++ b/runtime/doc/vim9class.txt @@ -1,4 +1,4 @@ -*vim9class.txt* For Vim version 9.1. Last change: 2025 Aug 27 +*vim9class.txt* For Vim version 9.1. Last change: 2025 Nov 10 VIM REFERENCE MANUAL by Bram Moolenaar @@ -766,7 +766,7 @@ The following builtin methods are supported: A class method cannot be used as a builtin method. Defining an interface ~ - *Interface* *:interface* *:endinterface* + *interface* *Interface* *:interface* *:endinterface* An interface is defined between `:interface` and `:endinterface`. It may be prefixed with `:export`: >