[vim/vim] runtime/doc/vim9.txt - Section 4 updated (PR #18610)

70 views
Skip to first unread message

Peter Kenny

unread,
Oct 20, 2025, 2:44:59 PMOct 20
to vim/vim, Subscribed

vim9.txt fixes and enhancements: Section 4

This is quite a large update. Section 4 is just under 1,000 lines now, which is around twice the extent. Many of the additional lines are to include educational, sourceable examples.

Locations of changes are indicated by reference to headings and *tags* in the updated file rather than line numbers. That mostly works well, though some of the more heavily edited passages are trickier to compare easily 1:1 to the current help.

4. Types

*vim9-types*

  • The error tags appearing with the heading of section 4 are relocated:

    • *E1008*, *E1009*, *E1010*, and *E1012* are moved after the types table and the “no simple value can have the "void" type” example. They include one-line sourceable examples, and mostly relate to ill-formed declarations.
    • *E1013*, *E1029*, and *E1030* are moved to the passage containing the examples demonstrating legacy Vim script versus Vim9 script differences (i.e., under Stricter type checking).
  • “The following builtin types”, list is missing five types:

    • none
    • class
    • typealias
    • enum
    • enumvalue

    They are included now, and the order of the list is changed to the order of the values of v:t_TYPE. It’s helpful to have the types, their v:t_TYPE and their type() shown, so a tabular format is used. Applicable hot-links to v:t_TYPE, type(), and the v:t_ types are added too.

*E1031* *E1186*

  • “Trying to use a void ...”, now has an example demonstrating E1031 and E1186. Rather than their tags being inline, they are moved to the more usual location, before the paragraph.

*E1008* *E1009* *E1010* *E1012*

  • [The first paragraph and its examples are explained above]

  • “There is no array type...”, does not include tuple, which is interesting because tuple-type is introduced immediately after it. The second sentence addresses that, though now it focuses on the concept (“use a list or tuple”) leaving the sourceable code to demonstrate the syntax. The tangential memory allocation point is omitted because, although it is not wrong, it is trivial in the wider context (learning/understanding Vim9 script) so, it seems unnecessary. Also, “literal” is used rather than “constant” because, aside from being less confusing - a tuple is a constant - it aligns with:

    • Vim9script’s own terminology (see vim9-literal-dict)
    • Vim’s help tag structure (*literal-string*, *literal-Dict*, etc.), and
    • Terminology used in the most commonly referenced languages in Vim9 script (JavaScript/TypeScript, Python, and Dart).

*tuple-type*

  • The awkward, “more or less specific”, is reworded; using “the following” is simpler.

*vim9-func-declaration*, et al.

  • The tag, *vim9-partial-declaration*, is added.
  • To be consistent with other tags for *vim9-{type}-type*, *vim9-func-type* is added. That way, :h -type CTRL-D should reveal all the Vim9 script type tags.
  • “A partial and function...” puts more emphasis on the former and is a bit clunky. “A function (or partial)...” now introduces the list. Similarly, “more or less specific ways” is awkward and it is obvious from the examples. It is simpler saying, “the following ways”.
  • The paragraph starting, “The reference can also be a |Partial|...”, is reworked. By itself, the explanation is not necessarily easy to grasp. Further, there is no complete example at the hot-link destination, i.e., following |Partial| (in eval.txt). So, providing a complete, interactive example makes sense. It is only eight lines and should help not only those wanting to understand partials in Vim9 script, but also partials generally. A second example could be added (or used instead), though, perhaps that would be too much? The area of a circle example has the advantage of being simple and interactive. Using a dictionary, which would cover the second point in, “stores extra arguments and/or a dictionary”, could be added to eval.txt? Something like this:
	vim9script
	var animals = ['penguin', 'gnu', 'gopher', 'cat', 'python', 'camel']
	def Compare(key: string, a: string, b: string): number
	  var dic = { alpha: () => a < b, length: () => len(a) < len(b) }
	  return dic[key]() ? -1 : 1
	enddef
	const ALPHA: func(string, string): number = function(Compare, ['alpha'])
	const LENGTH: func(string, string): number = function(Compare, ['length'])
	echo $"Unsorted animals: {animals}"
	echo $"Sorted (alpha):   {animals->sort(ALPHA)}"
	echo $"Sorted (length):  {animals->sort(LENGTH)}"

*vim9-typealias-type*

  • The tag *vim9-typealias-type* is added (for the same reasons as explained, above). This is a distinct topic, so should have its own tag. It is covered in vim9class.txt too, though it should be here too as an overview in the context of explaining Vim9 script types generally.

  • “Custom types ...” had only a one-line example. The updated paragraph covers the requirement to start with a capital letter and provides a simple example to show how custom types can be used. There is some overlap with vim9class.txt, which also provides an example, though it feels helpful to provide more than incidental content in vim9.txt on this topic, and it is not long. It is also warranted because of the following point.

*E1105*

  • The *E1105* tag is relocated from “Stricter Type Checking” (which is around 280 lines later in vim9.txt now) because that error relates specifically to the typealias topic and so it is better here than in the comparative (to legacy Vim script) content. It is also relocated because its current location does not relate to what it claims to address (i.e., “- Using a number where a string is expected. ... *E1105*”). A simple example demonstrates E1105, which should be helpful for anyone going to the tag.

*vim9-class-type*, *vim9-object-type* and *vim9-interface-type*

  • The three tags are added for completeness and consistency, following the established approach outlined, above.

  • “And classes and interfaces can be used as types”: The current help only has a brief statement with incomplete, non-sourceable examples. A terse example cannot adequately demonstrate how class, object, and interface types work together, so a comprehensive interactive example is warranted. The complete example provided should be useful for readers wanting to understand how to use the three types. Like typealias, above, it includes output for type() and typename(), which should also help readers appreciate v:t_class (for class and interface) and v:t_object. It strikes the right balance:

    • detailed enough to show all three types (class, object, interface),
    • concise enough to be read on most screens without scrolling, and
    • practical enough to show a meaningful use case (i.e., not a foobar).
  • The text, “{not implemented yet}” is removed because it is not applicable now.

  • Note: Although there are some useful examples of using classes in vim9class.txt there are no complete examples of using interfaces, so, adding this example is helpful. (vim9class.txt probably should be updated too, but that is beyond the scope of this update.)

*vim9-enum-type* and *vim9-enumvalue-type*

  • The two tags are added for completeness and consistency.

  • There was no information in vim9.txt on enum or enumvalue types. A paragraph explaining them is added. (As noted at the outset, neither enum nor enumvalue is in the list of types, which is also addressed.)

  • A complete, interactive example demonstrating enum as a type is included. Similar to class, object, and interface, it’s not easy to provide a succinct, sourceable script, though the example covers a lot of ground. The type() and typename() information is presented too, which is particularly interesting because the type() values differ (as expected) for "Quad" (the enum itself) and "myQuad" (an enumvalue), yet their typename()s are both enum<Quad>.

Variable types and type casting

*variable types*

  • The fourth paragraph starting, “At compile time” is reworked. That is because that intro, and the suggested, “a bit inefficient”, are distractions. As the examples later show clearly, the key point is whether list<any> is used versus overtly checking the variable’s type, so, the paragraph is reworded.

*type casting*

  • The tag *E1104* is relocated to a few paragraphs later (where its applicable error is explained and demonstrated).

  • “To avoid this, use a type cast”, is adjusted too. Now it homes in on the key point, i.e., to get more specific type checking.

  • A sourceable example is added to demonstrate type casting. Both functions produce E1012 errors due to type mismatches, but the type checking occurs at different points. The example uses try/catch blocks to make it fully executable, revealing the different error messages.

  • “The semantics is that...”, is awkward, so it is changed to align with the revised points, above.

  • The line, "If a type is given where it is not expected you can get *E1272* .", is removed. It appears this is not an error that ever occurs? (There is no evidence of it in src/testdir; perhaps it was intended, though never implemented? The only instance of it appearing in the source code is in src/errors.h, "E1272: Using type not in a script context: %s", but there are no test files for it. So, it could be reinstated, though should only be reverted if it really is a reachable error, preferably with a demonstrable example.

  • Type casting on chained expressions is added because the point should be included, i.e., the type cast applies to the whole expression, not the first element within it.

*E1363*

  • It may not be immediately obvious how error *E1363* occurs, so it, along with |E1360| (another error close to the topic), are provided with sourceable examples. The *E1363* tag is relocated to before the passage.

Type inference

  • The opening paragraph has been expanded to connect to the points in the preceding section.

  • The example has been made complete, sourceable, and four more types are included. The output shows each variable’s value, its type() number (corresponding to v:t_* constants), and its typename(), which should help improve understanding.

  • “The type of a list and dictionary” has the tuple type added, and the paragraph adjusted to reflect the “mix of types” list, which is enhanced by including typename() as well as dictionary and tuple examples, which makes sense since the paragraph now introduces all three.

  • “The common type of function references” paragraph has been modified to improve readability and introduce the example, which is now sourceable.

  • The remainder of this sub-section has improved wording and examples. This includes addressing, “If the type is not declared then it is allowed to change”, which could be misinterpreted as meaning a var with no type explicitly stated may be changed, whereas that is not right because it will either be inferred as a type or be 'any' - the point is meant to be that a list literal or dictionary literal’s type may change, which is what is demonstrated now.

Stricter type checking

*type-checking*

  • Some small changes are made to make the examples clearer.

*E1206*

  • The tags *E1210* and *E1212*, located alongside *E1206*, are moved to separate examples because they are not examples of where “it works just as before”, whereas that is true for E1206. So, only E1260 remains as the tag relevant to the paragraph, i.e., errors universally common-to-both languages. (I expect that's right because using something other than a dictionary where one is required is unlikely to be accommodated in any instance whereas it is clear that numbers, strings, etc., may be coerced in legacy Vim script, e.g., 8 to v:true - as :if 8 | echo 'yes' | endif does - and so forth.)

*E1023* *E1024* *E1029* *E1030* *E1210* *E1212*

  • These tags have been brought together as a common group. That is, they are the instances:

    • not documented elsewhere with corresponding tags, and
    • where legacy Vim script does not error but Vim9 script does.

    Bringing them together is more helpful than the currently scattered arrangement. It would probably take a reader a while to think about the scenarios that may cause these errors; so, the examples provided should make it easier for readers to grasp the differences, including if following hot-links to the tags.

  • There are several other type-related errors in Vim9 script, which do not error in legacy Vim script. The ones included now are: E521, E928, E1037, E1072, E1135, E1138, and E1174). The reason for them appearing after the ones noted in the point above are that these are different in that they have documentation and corresponding tags elsewhere. This collection covers a lot more than in the current help, though it feels warranted given these are important distinctions. Hot-links are provided to the seven applicable tags.

    • NOTE: The E1037 differences are unusual, illustrating inconsistent treatment in Vim9 script regarding v:none versus v:null/null; this does not error when compared to a number or bool (or anything other than the “Specials”, v:none and v:null). Perhaps it is intentional behaviour, though it is an open issue, #17358 (labelled as a bug).
    • NOTE: # comments are added for the E messages in all instances of the vim9cmd commands other than E521 and E1138, which do not syntax highlight the comment correctly - they could be made vim9script, but that would add several lines and look inconsistent with the other examples. (The same applies to E1030's example, though its comment has been retained as it is not so glaring in appearance since it is all the same highlight group.)
  • The “One consequence...” paragraph is enhanced to explain that it applies whether declared or inferred. The example is also improved by making it sourceable, showing how in legacy Vim script there is no problem changing the type of a list whereas trying to use map() on the same list in Vim9 script results in an E1012 error because the type is inferred as list<number>.

  • This example in the current help is incorrect:

    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<any>"
        map(mylist, (i, v) => 'item ' .. i)
        # typename(mylist) == "list<string>", no error
    

    ...which is the same as this:

    vim9script
    var mylist = [1, 2.0, '3']
    map(mylist, (i, _) => $"item {i}")
    echo mylist->typename()  # list<any>
    

    Clearly, typename() does NOT change from list<any>. It can only become list<string> if mapnew() is used (logically, because then it is inferred that all the list items are strings). So, that is shown, now with an extended example and commenting.

  • Further examples and expanded explanations are provided in relation to the “subtle difference between using a list constant directly”, which does not feel as clear it could be. The complete examples, including the list literal and deepcopy() are wrapped up in a slightly longer “reasoning” explanation.

*E1158*

  • The extend() and extendnew() examples are separated (now located before tag *E1158*) from flatten() and flattennew() because the former are both allowed in Vim9 script – examples are provided showing that – whereas flatten() is prohibited entirely (producing an E1158 error) even for literals.

  • The funcref with specified arguments passage was quite condensed. It now progresses clearly, with complete examples. It concludes with what had not been covered, which is, in some scenarios, any may allow for mixed types.

  • The funcref with no arguments specified explanation is made clearer and has a sourceable example. The FlexArgs funcref shows using a string-returning
    function with:

    • one string argument, and
    • a variable-sized list.

*E1211* to ... *E1534*

  • The current help provides only a “wall” of error tags with one generic sentence. Without examples, users encountering this may not easily determine what causes the errors nor how to fix them, especially if they :h E{nnnn} wanting to find out more about a specific error. Sourceable one-line examples of 25 of the 28 errors are included, which is more helpful.

    • Pre-empting potential maintenance concerns: Type-checking errors are probably mostly stable (except, e.g., if a type is added like tuple, which should be rare). If a function’s type requirements change, the corresponding error may need changing here too, though updating it here would require just a one-line change.
    • Line length: vim9 is used here rather than full commands to maximise the length of the truncated error messages in comments, keeping to <80 characters text width. Error messages are vertically aligned to aid readers’ ability to scan the “list”.
  • The three error tags, *E1227*, *E1250*, and *E1252*, are separated and noted as “Reserved for future use”. There appears to be no current builtin functions that produce these errors? This approach maintains the existing tags as placeholders, which presumably were included so that if/when these errors are applicable in future, their help entries can be easily located?

Categories of variables, defaults and null handling

  • The current help provides only three generic examples (one per category) without demonstrating actual behaviour. The revision provides comprehensive, sourceable examples for all 13 types, showing each type’s default value, its empty() status, and whether it equals null. This clarifies and demonstrates important distinctions:

    • primitives are empty() but not null
    • only empty strings are null among containers, and
    • specialized types default to null.
  • The paragraph, “Vim does not have a familiar null value”, has had small refinements.

  • The examples under, “For a specialized variable” and “For a container variable” (showing how to clear specialized and container variables respectively) are separated into distinct code blocks because they demonstrate different clearing mechanics. Both examples are now complete and sourceable. The job example is particularly helpful as it provides a working, cross-platform demonstration (using &shell and &shellcmdflag with the O/S shell’s 'date' command), which is something absent in the current help documentation.

  • “The initialization semantics of container and specialized variables” sentence is separated from the containers-related sentence because the content was, and remains, separately explained.

  • The containers example is preceded with an itemised explanation, then demonstrated with a working example, showing the equivalence of all three declarations but also the difference between the null_list and either of the initialised or uninitialized empty list containers.

  • The job passage is mostly unchanged, though the example is now sourceable with an echoed equivalency expression demonstrating their indistinguishable nature.

  • The paragraph, “When a list...”, is updated to include tuple, and the point it makes is separated into two sentences to make it easier to understand. The updated, sourceable code block now echoes the typename() for the empty and null tuple, showing that both empty and null tuples default to tuple<any>.

  • The paragraph, “Declaring a function...”, is updated for a few reasons. First, wording improvements to relocate the cross reference to the end. Second, it is no longer, “particularly unique”, because, now that tuple has been added, it also has several ways of being declared. The next sentence now says, “those types are atypical”. The cross-references to |vim9-func-declaration|, |tuple-type|, and |variadic-tuple| conclude the paragraph.

*null-compare*

  • This is one of the trickiest passages. The current help’s flow did not work well. Although it included one of the few complete source-able examples, it was an indirect example of what not to do. Instead, now it starts with three distinct comparisons. They are followed by reinforcing statements regarding the non-transitive relationships of null, null_<type>, and empty container. A re-structured example, building on what was in the original help, is provided. It echoes the results in tabular form. A further conceptual paragraph is included, since this is not a common structure, so some rationale (for why it is what it is) may be useful for those used to different null treatment.

*null-anomalies*

  • The first paragraph is unchanged except “may chose”, which is fixed.

  • Much of *null_anomalies* section already contained very good, complete examples, though a few needed expansion/clarification.

  • The null-<type> section did not note that the point is covered in detail in the preceding section (i.e., *null-compare*). That’s been made clear, and the example simplified.

  • The “uninitialized string” explanation was incomplete. It noted that 's1 == null' is “unexpected” but did not explain either why this behavior occurs or how it differs from other container types. Also, it only shows s2 is null_string but doesn't show s1 is null_string, which would reveal the important fact that an uninitialized string is the same instance as null_string.

  • Also shown now is the crucial underlying implementation distinction: uninitialized strings being a null_string container whereas other containers are empty containers. All these things are addressed in the rewritten explanations and examples.

  • The static list following “An uninitialized variable...” is transformed into a two informative, sourceable examples. The update also addresses what would be invalid syntax if the user tried to take the code and execute it (i.e., the current help has var f: func...). That has been fixed, and an enum example is included now too.

  • The container variables example has been moved to below the NOTE regarding specialized variables to keep the note with the relevant content. The container variables example has been expanded to hammer home the distinction between empty {container} == null_ whereas empty {container} != null.


You can view, comment on, or merge this pull request online at:

  https://github.com/vim/vim/pull/18610

Commit Summary

  • ecd61da runtime/doc/vim9.txt - Section 4 updated

File Changes

(2 files)

Patch Links:


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610@github.com>

Yegappan Lakshmanan

unread,
Oct 20, 2025, 3:36:53 PMOct 20
to vim/vim, Subscribed
yegappan left a comment (vim/vim#18610)
  • The line, "If a type is given where it is not expected you can get E1272 .", is removed. It appears this is not an error that ever occurs? (There is no evidence of it in src/testdir; perhaps it was intended, though never implemented? The only instance of it appearing in the source code is in src/errors.h, "E1272: Using type not in a script context: %s", but there are no test files for it. So, it could be reinstated, though should only be reverted if it really is a reachable error, preferably with a demonstrable example.

The function Test_misplaced_type() in the testdir/test_vim9_script.vim file tests for the E1272 error.
You can see the output of this test by running the following command:

:call term_dumpload('testdir/dumps/Test_misplaced_type.dump')

So this error code should not be removed.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3423464196@github.com>

Peter Kenny

unread,
Oct 20, 2025, 4:52:44 PMOct 20
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

So this error code should not be removed.

Thanks, that error code was driving me mad trying to find a way to replicate it. How's this for reverting (and also demonstrating) it?

						*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.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3423677517@github.com>

Yegappan Lakshmanan

unread,
Oct 20, 2025, 9:31:48 PMOct 20
to vim/vim, Subscribed
yegappan left a comment (vim/vim#18610)

So this error code should not be removed.

Thanks, that error code was driving me mad trying to find a way to replicate it. How's this for reverting (and also demonstrating) it?

						*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.

Looks good to me.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3424325119@github.com>

dkearns

unread,
Oct 21, 2025, 8:21:09 AMOct 21
to vim/vim, Subscribed
dkearns left a comment (vim/vim#18610)

@errael


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3426314907@github.com>

errael

unread,
Oct 22, 2025, 4:35:33 PMOct 22
to vim/vim, Subscribed
errael left a comment (vim/vim#18610)

Wow; great work. Here's some random thoughts.

Having more examples is good, but I wonder if it makes it less useful as a
reference since there's so much more text. Should there be both a reference and
a tutorial? The reference could have links to the examples in the tutorial. I'm
not really sure how I feel about this one way or the other.

Should all the examples for help be in a test?

Is there too much implementation details/assumptions? (I'm not saying there is)
For example, around line 1927 "However, sometimes there will be an error in
Vim9", there are many examples. Could implementation be changed so these
examples are no longer accurate? In particular, there may be some things that
are currently errors, whereas a different implementation would no longer get an
error. I guess this situation is handled if there are tests that include all the
examples.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3434121633@github.com>

errael

unread,
Oct 22, 2025, 4:42:38 PMOct 22
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

At original text line 1747, there is

FuncVA = (...v: list): number => v # OK, any runtime check

Maybe an example that compiles OK, but gets a runtime error would help to convey the compile/runtime difference.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3367480040@github.com>

errael

unread,
Oct 22, 2025, 4:52:52 PMOct 22
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  Types are checked for most builtin functions to make it easier to spot
-mistakes.
+mistakes.  The following one-line |:vim9| commands demonstrate many of those

Shouldn't "builtin" or "builtin functions" be mentioned (in lieu of "one-line") since that's what it's
about?


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3367506730@github.com>

errael

unread,
Oct 22, 2025, 4:56:37 PMOct 22
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

With the above example removed, there is no longer an example of container variable, initialized
to a null_type, being compared to null.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3367516135@github.com>

errael

unread,
Oct 22, 2025, 4:58:19 PMOct 22
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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_<type> in a comparison.  That is because,
+in Vim9 script, evaluation of:
⬇️ Suggested change
-in Vim9 script, evaluation of:
+in Vim9 script, evaluation of compare of:


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3367523354@github.com>

Peter Kenny

unread,
Oct 22, 2025, 8:30:38 PMOct 22
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

Wow; great work. Here's some random thoughts.

Thanks. It snowballed when I was writing Vim9 script plugins (with several in various stages of development, mostly due to the sidetrack of updating vim9.txt), trying to learn more but regularly hitting dead ends with the documentation. I found it had lots of incomplete/non-demonstrated material, which, especially for a new language, made the learning curve much steeper. It'd also be awesome to see Vim9 script take off - I love using it. (Many thanks to the devs!)

Having more examples is good, but I wonder if it makes it less useful as a reference since there's so much more text. Should there be both a reference and a tutorial? The reference could have links to the examples in the tutorial. I'm not really sure how I feel about this one way or the other.

I think the same, though have equivocal feelings too. There is a large grey area of what could be in this particular help file versus what could be spun off into a vim9tutorial.txt, vim9examples.txt, or suchlike. If it did go that way, cross references from vim9.txt, using the same Section and subsection structure, would probably be the way to go. A similar approach could be applied to vim9class.txt (vim9classexamples.txt?).

That said, I don't think it mattes a lot either way. That is because, unless the examples got so over the top that you couldn't follow the help (and I don't think it's there, yet anyhow), having working examples following explanations is helpful ... unless I'm in a minority of those who don't learn better like that?

If it remains largely as-is as PR-ed, it works both as a reference for those jumping to a tag or as a tutorial (e.g., learning about Vim9 script types as a thorough overview). Whether it's better together or separated is probably a continuum of opinions.

Is there too much implementation details/assumptions? (I'm not saying there is) For example, around line 1927 "However, sometimes there will be an error in Vim9", there are many examples. Could implementation be changed so these examples are no longer accurate? In particular, there may be some things that are currently errors, whereas a different implementation would no longer get an error. I guess this situation is handled if there are tests that include all the examples.

That's a great question, and is one I struggled with. What is clear, though, is that E1023, E1024, E1029, E1030, E1210, and E1212 examples need to stay as-is because they relate to the tags and appear nowhere else. The others are more debatable, though they are definitely distinctly errors versus Vim script where they do not error. So, you won't find them explained that way elsewhere since the help explanations default to Vim script outside of vim9*.txt, albeit sometimes providing "but in Vim9 script" information. Consequently, at the moment, you'll sometimes find Vim script explanations/examples in one place(s) and failing Vim9 script in another/others.

To illustrate, in the update, E928 has:

  - Not using a string when as string is required (|E928|): >vim

	let &langmenu = 42
	vim9cmd &langmenu = 42  # E928: String required

The problem is, at *E928* in message.txt all you get is this:

						*E928* *E889*
  E928: String required ~
  E889: Number required ~

These happen when a value or expression is used that does not have the
expected type.

So, if the examples demonstrating the differences were removed from vim9.txt, moving them to the locations where the tags could work; in the example.txt instance:

...
These happen when a value or expression is used that does not have the
expected type.  That occurs more frequently in Vim9 script because of
its stricter type checking, e.g.: >vim

	let &langmenu = 42
	vim9cmd &langmenu = 42  # E928: String required

Back in vim9.txt, a list could be retained with only the current "extra" examples of the Vim script v. Vim9 script differences:

Other examples where Vim script tolerates type mismatches but Vim9 script
doesn't:

  - Not using a string when as string is required (|E928|)
  - Comparing a |Special| with 'is', in some instances (|E1037|, |E1072|)
  - Using a string where a bool is required (|E1135|)
  - Using a bool as a number (|E1138|)
  - Not using a string where an argument requires a string (|E1174|)

Thoughts? As to your second point on this - these are not likely to change, E1037 aside, which I've noted.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3434657149@github.com>

Peter Kenny

unread,
Oct 23, 2025, 3:20:29 AMOct 23
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  Types are checked for most builtin functions to make it easier to spot
-mistakes.
+mistakes.  The following one-line |:vim9| commands demonstrate many of those

The one-line sentence is to focus on the vim9 v. vim9cmd, which is used everywhere else. When updating Section 5, there was a preference noted to use the full command preferably. That's not done for the one-line collection as it makes for an even more truncated column of comments. I think the sentences, read together, make it clear this is about builtin functions, though it could be repeated for the avoidance of doubt - this?

Types are checked for most builtin functions to make it easier to spot
mistakes.  The following one-line |:vim9| commands, calling builtin functions,
demonstrate many such type-checking errors: >vim9


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3368548676@github.com>

errael

unread,
Oct 23, 2025, 11:40:23 AMOct 23
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  Types are checked for most builtin functions to make it easier to spot
-mistakes.
+mistakes.  The following one-line |:vim9| commands demonstrate many of those

I seem to have missed "builtin functions" in the previous line. diff-mania


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3370690437@github.com>

Peter Kenny

unread,
Oct 23, 2025, 2:28:36 PMOct 23
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

I think the list<any> example, i.e., FuncVA = (...v: list<any>): number => v, potentially is misleading in this context. Using list<any> provides no practical benefit when assigning to a single funcref type, which remains limited to the declared type, so you get runtime errors anyway if you pass values of the wrong type. It "works", but effectively only in a less safe way. Arguably, it's better either omitting it or, perhaps, discouraging it? A more complete example ...

vim9script
var FuncVA: func(...list<string>): number
# It is okay to use list<any> here, though v's items must be strings at runtime
FuncVA = (...v: list<any>): number => v->join('')->str2nr(16)
echo FuncVA('1', 'F', '6', '0', '0')->nr2char()  # 😀

(The FlexArgs example - a few lines later - demonstrates runtime flexibility.)


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3371859998@github.com>

Peter Kenny

unread,
Oct 23, 2025, 3:21:55 PMOct 23
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

Literals feel more focused. Using variables requires mentally tracking le and ln, whereas literals show immediately what is being compared. The principle is the same, though is conveyed better using literals (IMO). Nonetheless, if you think showing variables in the example is essential, the example could be adjusted to:

	vim9script
	var [le, ln] = [[], null_list]
	echo le == null_list    # true
	echo ln == null        # true
	echo le == null        # false

Alternatively (and better, I think) a Note could address it, e.g.:

	vim9script
	echo [] == null_list		# true
	echo null_list == null 		# true
	echo [] == null			# false

	  Note: This example uses literals, though the principle applies
		similarly to variables declared as [] and null_list.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3372154404@github.com>

Peter Kenny

unread,
Oct 23, 2025, 3:35:37 PMOct 23
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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_<type> in a comparison.  That is because,
+in Vim9 script, evaluation of:

Yes, focusing on the comparison is right, though on reading it again, evaluation of is a distraction, so this would be even better:

For familiar null compare semantics, where an empty container is not equal to
a null container, do not use null_<type> in a comparison.  That is because,
in Vim9 script, comparing:
  - an empty container to null_<type> returns `true`, and
  - null_<type> to `null` returns `true`, but
  - an empty container to `null` returns `false`.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3372221611@github.com>

errael

unread,
Oct 23, 2025, 11:04:09 PMOct 23
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

I wrote the comment only based on seeing the word 'runtime check'. After your comment and not having used vim9 in quite a while, I had to go back and try to understand this stuff; in particular what this section is about and how varargs works. I'd say it's more or less about how the compiler handles varargs funcref assignments and implications of particular assignments.

The idea of the example in question is about an assignment to a strictly typed funcref that works at compile time and ends up with runtime errors. Consider a function that takes a variable number of args, handled in pairs of number, string. Invoked like F(1, '1', 2, '2'). The declaration must use any. The following gets a runtime error.

vim9script
var FuncVA: func(...list<string>): number
# This assignment gets no type errors, but there will be runtime errors
FuncVA =  (...v: list<any>): number => {
    # takes pairs of int,number like F(1, '1', 2, '2')
    var i = 0
    while i < len(v)
        echo v[i] + str2nr(v[i + 1])
        i += 2
    endwhile
    return 33
}

echo typename(FuncVA)
FuncVA('0', '1')

Just another example of how any messes with the type system.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3374145607@github.com>

errael

unread,
Oct 23, 2025, 11:17:39 PMOct 23
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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_<type> in a comparison.  That is because,
+in Vim9 script, evaluation of:

Yeah, better


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3374186518@github.com>

errael

unread,
Oct 23, 2025, 11:46:24 PMOct 23
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

This area starts with For familiar null compare semantics, which means what to do in your code to see a familiar comparison if some_var == null. The removed example shows how to achieve that. As mentioned elsewhere do not use null_<type> in a comparison, it's also an example of where to use null_<type> and where to use null.

vim9's null handling is a nightmare. Explaining more about how to use it (not what it's doing) was a great weakness of the previous docs. I haven't really looked at this PR in that context.

The suggested alternative shows how it works, not what to do in your code. It's like saying: this is how it works internally, now you figure out how to get something that looks familiar. And isn't this a repeat of what appear in the null-details section?


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3374283554@github.com>

errael

unread,
Oct 24, 2025, 3:52:08 PMOct 24
to vim/vim, Subscribed
errael left a comment (vim/vim#18610)

Is there too much implementation details/assumptions? (I'm not saying there is) For example, around line 1927 "However, sometimes there will be an error in Vim9", there are many examples. Could implementation be changed so these examples are no longer accurate? In particular, there may be some things that are currently errors, whereas a different implementation would no longer get an error. I guess this situation is handled if there are tests that include all the examples.

That's a great question, and is one I struggled with. What is clear, though, is that E1023, E1024, E1029, E1030, E1210, and E1212 examples need to stay as-is because they relate to the tags and appear nowhere else.

I've thought that multiple same help tags should be supported. Then could do :tnext or maybe
:hnext or maybe a popup with a little info about each reference to the error. Allowing only one tag negatively impacts in a big way referencing where the errors are applicable.

The others are more debatable, though they are definitely distinctly errors versus Vim script where they do not error. So, you won't find them explained that way elsewhere since the help explanations default to Vim script outside of vim9*.txt, albeit sometimes providing "but in Vim9 script" information. Consequently, at the moment, you'll sometimes find Vim script explanations/examples in one place(s) and failing Vim9 script in another/others.

My comment was not considering the legacy vs vim9 differences. Rather vim9 evolving. It's not all that unusual for a builtin to be extended to accept additional types/arguments. That can mean different error codes which makes the help erroneous/out-of-date; that's what I meant about too much detail. I guess that points out the usefulness of tests for examples.

Should all the examples for help be in a test?

I haven't seen any comments on this. Some meta info/pointers so that tests could automatically be generated for examples would be cool.

BTW, another example of the usefulness of tests. I came across what looks like a bug in which error is used for a builtin that gets called with bad args. The PR doc, around line 2172

vim9 getcharstr('9')              # E1235: Bool or number required for

and :he getcharstr(' says "number" isn't allowed`". If this ever gets fixed the help would be out of date.

To illustrate, in the update, E928 has:

  - Not using a string when as string is required (|E928|): >vim
[snip]
So, if the examples demonstrating the differences were removed from `vim9.txt`, moving them to the locations where the tags could work; in the `example.txt` instance:

...

Another example of where having only one tag makes it hard to have good documentation.

Thoughts? As to your second point on this - these are not likely to change, E1037 aside, which I've noted.

I don't agree with your conclusion that things don't change.

I guess a key point is that the help infrastructure could use an update. This PR may exacerbate/show some problems with the infrastructure.

@dkearns @yegappan there's some general discussion about help issues in this post. Comments?


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3444692693@github.com>

Peter Kenny

unread,
Oct 25, 2025, 2:04:39 PMOct 25
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

The suggested alternative shows how it works, not what to do in your code. It's like saying: this is how it works internally, now you figure out how to get something that looks familiar.

Sorry, I'd misinterpreted what you were asking. You mean this current passage?

For familiar null compare semantics, where a null container is not equal to
an empty container, do not use null_<type> in a comparison: >
	vim9script
	def F(arg: list<string> = null_list)
	    if arg == null
	       echo "null"
	    else
		echo printf("not null, %sempty", empty(arg) ? '' : 'not ')
	    endif
	enddef
	F()		# output: "null"
	F(null_list)	# output: "null"
	F([])		# output: "not null, empty"
	F([''])		# output: "not null, not empty"

When I was reading that I thought it was better split into the concept (i.e., the three lines of the literal comparisons), then covering all the points above, but in tabular output:

This non-transitive relationship of null, null_<type>, and empty container
is further demonstrated in this example: >vim9

	vim9script
	echo '            null  null_list  empty'
	def NullCompare(n: string, t: any)
	  echo printf('%9S%7S%9S%7S', n, t == null, t == null_list, empty(t))
	enddef
	NullCompare('null', null)		# null
	NullCompare('null_list', null_list)	# null container
	NullCompare('[]', [])			# empty container
image.png (view on web)

The null handling is challenging, yes. Even if it's a bit repetitive, covering it from a few angles is not necessarily a bad approach because it can take a while to get your head around it. If this is not as good for showing what to do in your code, maybe I missed the mark in this instance. Reverting to a similar example as what is there currently is fine if that conveys the point better. What do you think?


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3380172103@github.com>

Peter Kenny

unread,
Oct 25, 2025, 2:37:00 PMOct 25
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

Agreed. I think we're saying the same thing, though your example specifically demonstrates how any "messes with the type system", postponing checking to runtime. However, my question was whether:

  • it's worth noting it is possible, though not a good idea / discourage it, or
  • omit it entirely.

Your example demonstrates the runtime failure clearly whereas I'd only commented/hinted to it. To show the pitfall, a modified version of mine works:

image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3380189598@github.com>

errael

unread,
Oct 25, 2025, 5:55:51 PMOct 25
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

Actually, the modified version you have does not show the pitfall. Keep in mind that stuff at the top level vimscript is interpreted, not compiled. Putting your example in a function as seen here

vim9script

var FuncVA: func(...list<string>): number

FuncVA = (...v: list<any>): number => v->join('')->str2nr(16)

def F()
    echo FuncVA(1, 'F')
enddef
F()

produces a compile error, not a runtime error. Note the signature of FuncVA is used at compile time.

Error detected while compiling /tmp/xxx.vim[10]..function <SNR>50_F:
line    1:
E1013: Argument 1: type mismatch, expected string but got number

Agreed. I think we're saying the same thing, though your example specifically demonstrates how any "messes with the type system", postponing checking to runtime. However, my question was whether:

* it's worth noting it is possible, though not a good idea / discourage it, or

* omit it entirely.

Strongly typed languages should not get type errors at runtime, more or less. How, and how much, the various vim9 type system pitfalls should be pointed out is an open question. Since your example does not show what you thought it did, maybe pointing it out more is the better option. I know that my example was pretty verbose.

Your example demonstrates the runtime failure clearly whereas I'd only commented/hinted to it. To show the pitfall, a modified version of mine works:

image


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3380255711@github.com>

Peter Kenny

unread,
Oct 25, 2025, 6:20:00 PMOct 25
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

I've thought that multiple same help tags should be supported. Then could do :tnext or maybe :hnext or maybe a popup with a little info about each reference to the error. Allowing only one tag negatively impacts in a big way referencing where the errors are applicable.

Perhaps, though couldn't that lead to unintended consequences? For example, which tag instance would be the primary tag? Maybe there could be a way to distinguish the primary tag versus subordinate tags, though that would add complexity. For example, in the three listed in the screenshot below, the *E86* tag is the last item. That may not be the one a user would jump to initially if other locations had that tag too? Worse, what if another location was only a limited example rather than the prime one?

Together, :helpgrep and :cope work fine for unambiguous text like the error code tags. In this example, \<E86[^0-9] since the number is only two digits. That finds the tag, hot-links to the tag, comments in script examples referencing the tag, and references to the tag generally:

image.png (view on web)

So, provided each location an error is applicable has a distinct reference to the error number, it's 'enabled' already and requires no development. It also may be considered better in that it's relatively easy to spot the tag *E86*, versus hot-links |E86| versus inline references to E86.


I don't agree with your conclusion that things don't change.

You're right. What I should have said is some things are less likely to change than others. However, from a maintenance perspective, when they do change, finding and updating the locations in the help where they appear should not be too hard, as shown above.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3447825349@github.com>

errael

unread,
Oct 25, 2025, 6:22:46 PMOct 25
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

The null handling is challenging, yes. Even if it's a bit repetitive, covering it from a few angles is not necessarily a bad approach because it can take a while to get your head around it. If this is not as good for showing what to do in your code, maybe I missed the mark in this instance. Reverting to a similar example as what is there currently is fine if that conveys the point better. What do you think?

If I'm coding, and I do :help null-compare I want an example of code that looks like what I might want to do along with how to use the example code; details (or a reference), of why the example code is the way it is, are useful if the example is not clear to me or if I want/need to dig in for a deeper understanding. Not having, removing, examples of code you might want in your application seems like the wrong direction.

I don't mind some repetition; of course too much repetition, rather than pointing elsewhere for details, becomes bloat.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3380336193@github.com>

errael

unread,
Oct 26, 2025, 12:02:00 PMOct 26
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

Not having, removing, examples of code you might want in your application seems like the wrong direction.

Huh, this might play into the discussion of reference vs tutorial.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3381195731@github.com>

errael

unread,
Oct 26, 2025, 2:50:38 PMOct 26
to vim/vim, Subscribed
errael left a comment (vim/vim#18610)

I've thought that multiple same help tags should be supported. Then could do :tnext or maybe :hnext or maybe a popup with a little info about each reference to the error. Allowing only one tag negatively impacts in a big way referencing where the errors are applicable.

Perhaps, though couldn't that lead to unintended consequences? For example, which tag instance would be the primary tag? Maybe there could be a way to distinguish the primary tag versus subordinate tags, though that would add complexity. For example, in the three listed in the screenshot below, the *E86* tag is the last item. That may not be the one a user would jump to initially if other locations had that tag too? Worse, what if another location was only a limited example rather than the prime one?

You're right, I agree that simply having multiple same tag isn't a very good extension to help documents.

Together, :helpgrep and :cope work fine for unambiguous text like the error code tags.

I'm actually a pretty lightweight vim user. I don't think I even knew about, or maybe it's remembered, :helpgrep. I do recall instances where I've grepped the actual help text from the console; thanks for the tip. And maybe in the past I've used :copen. Looking at :he :copen I don't see how it's useful here. If I :source a vim9script which gets a compilation error, and then do :copen, the quickfix list is empty. Ah, I get it; the quickfix list is populated with the results of :helpgrep.

I'm not sure what assumptions are right about the target user's skillset, like using helpgrep or understanding help text syntax that appears in the quickfix window. But a script, e.g. :HelpE xxx, could produce something more appropriate. With HelpE in mind it would be useful to have some guidelines for presenting error codes to give good information about any given error code. But still not a good as additional help syntax, but probably good enough. But considering that help pages would have to be written to present error code references in a useful way so that the output of :HelpE xxx is good without requiring going to each page. Having help syntax for error codes, or multiple "sub/alt-tags" in general, probably makes it easier for developers; this assumes something like :HelpE xxx would actually be worthwhile.

Of course this discussion doesn't belong in this thread...

[snip]

I don't agree with your conclusion that things don't change.

You're right. What I should have said is some things are less likely to change than others. However, from a maintenance perspective, when they do change, finding and updating the locations in the help where they appear should not be too hard, as shown above.

From a maintenance perspective, having tests that include examples is much more effective for keeping certain parts of the help text accurate than a manual procedure. Especially considering that the manual procedure may be skipped; not sure how likely that is, may be less likely than my pessimistic view.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3448776613@github.com>

Peter Kenny

unread,
Oct 26, 2025, 3:54:05 PMOct 26
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

Together, :helpgrep and :cope work fine for unambiguous text like the error code tags.

... Ah, I get it; the quickfix list is populated with the results of :helpgrep.

I'm not sure what assumptions are right about the target user's skillset, like using helpgrep or understanding help text syntax that appears in the quickfix window. But a script, e.g. :HelpE xxx, could produce something more appropriate. ....

Of course this discussion doesn't belong in this thread...

Yes, we're going into non-Vim9 script types territory for sure. Interesting questions, though. My take on the target user's skillset, at least while reviewing and re-writing vim9.txt, is that complete, meaningful (non-foobar) examples facilitate learning, especially for non-experts. I am, or at least was, fairly proficient in an extremely niche/legacy language and found explanations in its help were not particularly helpful because they did not include enough code-complete examples to aid learning, meaning there was lots of trial and error.

Closing this out, some help-extending functions/commands could be a potential runtime/pack/dist/opt plugin candidate? A rudimentary script for what you suggest:

vim9script
# helpgrep \<{topic} and open the help and Quickfix List of results
def HelpQ(s: string): void
  execute $"helpgrep \\<{s}"
  execute "cope"
enddef
command -nargs=+ HelpQ HelpQ(<q-args>)

Maybe spin off a Discussion? (and close this thread here now)


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3448873355@github.com>

Peter Kenny

unread,
Oct 27, 2025, 1:31:17 PMOct 27
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +Though, <any> may be used to accommodate mixed types: >vim9
+

I see your point now - I was not distinguishing between runtime and compiling errors - though I'm not convinced it needs to be included. However, if there's consensus it adds value, it could be covered with a Note and examples following the <any> paragraph (using a simpler string and v: any combo as I've done here):

And <any> may be used to accommodate mixed types: >vim9

	vim9script
	var FlatSort: func(...list<any>): any
	FlatSort = (...v: list<any>) => flattennew(v)->sort('n')
	echo FlatSort(true, [[[5, 3], 2], 4])  # Echoes [true, 2, 3, 4, 5]
<
	  Note: Using <any> 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)

		    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()
<


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3384670704@github.com>

Peter Kenny

unread,
Oct 27, 2025, 4:05:22 PMOct 27
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

If I'm coding, and I do :help null-compare I want an example of code ...

Yes, I do too. I remember now why I disliked the current help's example:

  • The defaulted arg: list<string> = null_list was distracting because it was only there to accommodate calling with F() (which isn't needed in the context of the three comparisons)
  • Including F(['']) further diluted the message with self-evident information not related to the comparison point (# output: "not null, not empty"), and
  • Echoed output including whether the container is empty was a further distraction from the key message about "null-comparing" [], null_<type>, and null.

On reflection, I think this focused version would work better for the *null-compare* passage (with the result of the sourced code shown too):

image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3385260971@github.com>

errael

unread,
Oct 28, 2025, 1:24:31 PMOct 28
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

If I'm coding, and I do :help null-compare I want an example of code ...

Yes, I do too.

Actually, the complete quote more accurately expresses what I meant.

If I'm coding, and I do :help null-compare I want an example of code

that looks like what I might want to do along with how to use the example code; ...

I don't see how your suggested example would ever appear in an actual program. It doesn't even have the ubiquitous "if some_var == null" which I would expect to see in an example after doing :help null-compare. It also gives misleading information about detecting empty container.

The idea with the current help's example is to show a null check for a container. It also shows, after determining that the container is not null, an empty check. Instead of empty() could use len(), but empty is preferred; for i in l could also be used. These choices are up to the developer and don't belong in the example.

I remember now why I disliked the current help's example:

The current example is "complete" and shows invoking the function with all possible relevant argument combos. Also, a real world example with have things not directly the "point". Like a function declaration, or else clause.

* The defaulted `arg: list<string> = null_list` was distracting because it was only there to accommodate calling with `F()` (which isn't needed in the context of the three comparisons)

I agree that handling invoking the function without arguments might be overkill.

* Including `F([''])` further diluted the message with self-evident information not related to the comparison point (`# output: "not null, not empty"`), and

I disagree (not super strongly). In a real world example, handling empty and not empty may be something to consider.

* Echoed output including whether the container is **`empty`** was a further distraction from the key message about "null-comparing" `[]`, `null_<type>`, and `null`.

Both the current and proposed description of null-compare example discuss empty and show detecting an empty container. For an example of detecting empty() is the right choice. The proposed example implies that empty_container == null_<type> is the way to check for empty. But that uses code the description says should never be used.

On reflection, I think this focused version would work better for the *null-compare* passage (with the result of the sourced code shown too):

As mentioned, the proposed example is not an example of code that might be in a program. Parts of it may be useful in the help for describing why a real example is the way it is.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3389961477@github.com>

Peter Kenny

unread,
Oct 29, 2025, 2:46:04 PM (13 days ago) Oct 29
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

My focus is to home in specifically on what is introduced, i.e., "where an empty container is not equal to a null container, do not use null_<type> in a comparison". I could, but won't go into a philosophical debate on some of your points because I want to wrap this PR and, since it's about the only sticking point left, let's try to build an example we agree on. If a not-too-long "production-ready" example can demonstrate the point, great. How about this?

						*null-compare*
For familiar null compare semantics, where an empty container is not equal to
a null container, do not use null_<type> in a comparison.  That is because,
in Vim9 script, although null_<type> == `null`, comparing:

  - an empty container to `null` is `false`, but
  - an empty container to null_<type> is `true`

So, compare against `null`, not null_<type>.  For example: >vim9

	vim9script
	var goldfinger: list<string> = ['007', '008']
	var octopussy: list<string> = ['007', '009']
	def Search(query: string): list<string>
	  if query == "\r"  # Enter pressed with no character
	    return null_list
	  elseif query =~ '^g'
	    return goldfinger
	  elseif query =~ '^o'
	    return octopussy
	  else
	    return []
	  endif
	enddef
	echo "goldfinger (g) or octopussy (o)?: "
	var in: string = getchar()->nr2char()
	var result: list<string> = in->Search()
	if result == null  # <<< DO NOT USE null_list HERE!
	  echo "Error: Nothing entered"
	elseif result->empty()
	  echo $"No matches for {in}"
	else
	  echo $"{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.

If you don't think this example is suitable I think you'll have to provide what you consider a production-ready example for this could look like.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3395400656@github.com>

errael

unread,
Oct 29, 2025, 4:30:32 PM (13 days ago) Oct 29
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

Works for me.

not-too-long

That might be a different philosophical discussion:) Along with is "production-ready" needed or is "framework" good enough?

Can consider trimming a few lines

vim9script
var bond_films: dict<list<string>> = {g: ['007', '008'], o: ['007', '009']}
def Search(query: string): list<string>
  if query == "\r"  # Enter pressed with no character
    return null_list
  endif
  return bond_films->get(query, [])
enddef
echo "goldfinger (g) or octopussy (o)?: "
var in: string = getcharstr()
var result: list<string> = in->Search()
if result == null  # <<< DO NOT USE null_list HERE!
  echo "Error: Nothing entered"
elseif result->empty()
  echo $"No matches for '{in}'"
else
  echo $"{result}"
endif


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3396053291@github.com>

errael

unread,
Oct 29, 2025, 4:42:36 PM (13 days ago) Oct 29
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

If one is really in the mood to squeeze

def Search(query: string): list<string>
  # "\r" is Enter pressed with no character
  return query == "\r" ? null_list : bond_films->get(query, [])
enddef


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3396132274@github.com>

Peter Kenny

unread,
Oct 30, 2025, 2:19:38 PM (12 days ago) Oct 30
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 						*null-compare*
-For familiar null compare semantics, where a null container is not equal to
-an empty container, do not use null_<type> in a comparison: >
-	vim9script
-	def F(arg: list<string> = 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

Looks good. A few more lines squeezed out and we're done.

	vim9script
	var bonds: dict<list<string>> = {g: ['007', '008'], o: ['007', '009']}
	def Search(query: string): list<string>
	  return query == "\r" ? null_list : bonds->get(query, [])
	enddef
	echo "Goldfinger (g) or Octopussy (o)?: "
	const C: string = getcharstr()
	var result: list<string> = 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


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3401016378@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:45:18 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +	def NoReturn(): void
+	enddef
+	try
+	    const X: any = NoReturn()
+	catch
+	    echo v:exception	  # E1031: Cannot use void value
+	    try
+	        echo NoReturn()
+	    catch
+	        echo v:exception  # E1186: Expression does not result in a ...
+	    endtry
+	endtry

No-value returns are permitted in no-value result type
functions, so NoReturnValue or similar name is more fitting.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406609044@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:45:25 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

>  
-	:class MyTemplate<Targ>
-	:var mine: MyTemplate<number>
-	:var mine: MyTemplate<string>
+	vim9script
+	type Ln = list<number>
+	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
⬇️ Suggested change
-classes, objects, and interface: >vim9
+classes, objects, and interfaces: >vim9


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406610045@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:46:13 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +	enum Quad
+	    Square('four', 'only'),
+	    Rhombus('opposite', 'no')
+	    var eq: string
+	    var ra: string
+	    def About(): string
+	        return $"\nA {this.name} has " ..
+	               $"{this.eq} equal sides and {this.ra} right angles\n\n"
+	    enddef
+	endenum

There are common builtin methods that can be implemented for
user-defined types (:help builtin-object-methods); string
is one of them and its implementation is an alternative to
About.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406614132@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:46:33 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +The difference is demonstrated in the following example.  In function "NTC",
+Vim infers the expression type "[1, b:two]" as list<any>, then verifies
+whether it can be assigned to the list<number> return type.  In function "TC",
+the type cast means Vim first checks whether "b:two" is a <number> type: >vim9
+
+	vim9script
+	b:two = '2'
+	const NTC: func = (): list<number> => {
+	    return [1, b:two]
+	    }
+	disassemble NTC  # 3 CHECKTYPE list<number> stack [-1]
+	try
+	    NTC()
+	catch
+	    echo v:exception .. "\n\n"  # expected list<number> but...
+	endtry
+	const TC: func = (): list<number> => {
+	    return [1, <number>b:two]
+	    }

NTC and TC are the names of Funcref variables of lambda
expressions that are associated with anonymous functions.
So, it is hardly "function NTC" or "function TC".


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406615649@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:47:01 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +The syntax of a type cast is:  "<" {type} ">".  White space isn't allowed
+either after the "<" or before the ">" (to avoid them being confused with
+smaller-than and greater-than operators).  Examples: >vim9
+
+	vim9cmd echo [1, <number g:num]   # E1104: Missing >
+	vim9cmd echo [1, <number >g:num]  # E1068: No white space allowed...
+	vim9cmd echo [1, < number>g:num]  # E15: Invalid expression ...

Why not write "<{type}>" instead of "<" {type} ">" and
leave out all ill-formed white-space-related examples? The
text already spells out the supported syntax.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406617040@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:47:35 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +  - 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 as string is required (|E928|): >vim
⬇️ Suggested change
-  - Not using a string when as string is required (|E928|): >vim
+  - Not using a string when a string is required (|E928|): >vim


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406618522@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:47:48 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +"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.
⬇️ Suggested change
-"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.
+"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.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406619436@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:48:06 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +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 deepcopied list, that type safety is
⬇️ Suggested change
-type.  For either a list literal or a deepcopied list, that type safety is
+type.  For either a list literal or a fully copied list, that type safety is


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406620178@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:48:14 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +	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 deepcopied 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 "<any>" it will not
⬇️ Suggested change
-If the item type was not declared or determined to be "<any>" it will not
+If the item type was not declared or determined to be "<any>", it will not


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406620707@github.com>

Aliaksei Budavei

unread,
Oct 31, 2025, 7:48:59 PM (11 days ago) Oct 31
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +Declaring a function (or partial) may be done in various ways.  A tuple may
+be declared in various ways too.  So, those types are atypical.

Punning aside, what is atypical about tuples and functions,
and what is typical otherwise?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406622939@github.com>

Peter Kenny

unread,
Nov 1, 2025, 9:42:40 AM (11 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +  - 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 as string is required (|E928|): >vim

Thanks. Fixed for the final update.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406903459@github.com>

Peter Kenny

unread,
Nov 1, 2025, 10:29:04 AM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +The syntax of a type cast is:  "<" {type} ">".  White space isn't allowed
+either after the "<" or before the ">" (to avoid them being confused with
+smaller-than and greater-than operators).  Examples: >vim9
+
+	vim9cmd echo [1, <number g:num]   # E1104: Missing >
+	vim9cmd echo [1, <number >g:num]  # E1068: No white space allowed....
+	vim9cmd echo [1, < number>g:num]  # E15: Invalid expression ...
  1. That sentence was one of the few I'd not adjusted in some way. It's better as you suggest, particularly given the following, "White space isn't...", sentence. I've changed it for the final update.
  2. The *E1104* tag is before the paragraph, so including the example of what it is caused by is consistent with what I've done elsewhere. The E1068 and E15 examples can be omitted as examples, sure, but are worth having as hot-links inline.

So, this is what that passage would be now:

						*E1104*
The syntax of a type cast is "<{type}>".  White space isn't allowed either
after the "<" (|E15|) or before the ">" (|E1068|), which avoids them being
confused with smaller-than and greater-than operators.  Omitting the
opening "<" (|E121|) or closing ">" is an error: >vim9

	vim9cmd echo [1, <number g:num]   # E1104: Missing >
<


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3406903309@github.com>

Peter Kenny

unread,
Nov 1, 2025, 2:20:23 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +Declaring a function (or partial) may be done in various ways.  A tuple may
+be declared in various ways too.  So, those types are atypical.

That replaced, Declaring a function, see |vim9-func-declaration|, is particularly unique. (Ignoring the superfluous "particularly") yes, it had been unique in that there are many ways it can be declared, func, func({type}, ...): {type}, etc. Once tuple was added, with its, tuple<type>, tuple<...list<type>>, etc., it meant function was no longer "unique" in that sense. Reading it again, though, adding "atypical" was not the best word choice. This, or something similar, would be better for the closing paragraph of that passage:

Tuples and functions (or partials) may be declared in various ways.
See |tuple-type|, |variadic-tuple|, and |vim9-func-declaration|.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407627475@github.com>

Peter Kenny

unread,
Nov 1, 2025, 2:49:53 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +	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 deepcopied 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 "<any>" it will not

Sure. Done.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407651265@github.com>

Peter Kenny

unread,
Nov 1, 2025, 2:52:03 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +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 deepcopied list, that type safety is

Thanks. Done.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407651819@github.com>

Peter Kenny

unread,
Nov 1, 2025, 2:53:21 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +"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.

Done.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407652158@github.com>

Peter Kenny

unread,
Nov 1, 2025, 2:56:58 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +	def NoReturn(): void
+	enddef
+	try
+	    const X: any = NoReturn()
+	catch
+	    echo v:exception	  # E1031: Cannot use void value
+	    try
+	        echo NoReturn()
+	    catch
+	        echo v:exception  # E1186: Expression does not result in a ...
+	    endtry
+	endtry

Sure. Changed to NoReturnValue.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407653154@github.com>

Peter Kenny

unread,
Nov 1, 2025, 3:12:33 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
-	:class MyTemplate<Targ>
-	:var mine: MyTemplate<number>
-	:var mine: MyTemplate<string>
+	vim9script
+	type Ln = list<number>
+	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

There are two classes (Circle and Square), two objects (myCircle and mySquare), and one interface (Shape), so it's correct as, "and interface:".

(The shapes container variable is also echoed to provide useful additional information on the interface-typed objects, which could be helpful for complete understanding.)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407657017@github.com>

Aliaksei Budavei

unread,
Nov 1, 2025, 7:26:08 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +The following builtin types, each with its corresponding |v:t_TYPE| and |type()|
+value, are supported:
+
+	builtin type			|v:t_TYPE|	|type()|
+	--------------------------	------------	------
+	number				|v:t_number|	  0
+	string				|v:t_string|	  1
+	func				|v:t_func|	  2
+	func: {type}			|v:t_func|	  2
+	func({type}, ...)		|v:t_func|	  2
+	func({type}, ...): {type}	|v:t_func|	  2
+	list<{type}>			|v:t_list|	  3
+	dict<{type}>			|v:t_dict|	  4
+	float				|v:t_float|	  5
+	bool				|v:t_bool|	  6
+	none				|v:t_none|	  7
+	job				|v:t_job|	  8
+	channel				|v:t_channel|	  9
+	blob				|v:t_blob|	 10
+	class				|v:t_class|	 12
+	object				|v:t_object|	 13
+	typealias			|v:t_typealias|	 14
+	enum				|v:t_enum|	 15
+	enumvalue			|v:t_enumvalue|	 16
+	tuple<{type}>			|v:t_tuple|	 17
+	tuple<{type}, {type}, ...>	|v:t_tuple| 	 17
+	tuple<...list<{type}>>		|v:t_tuple| 	 17
+	tuple<{type}, ...list<{type}>>	|v:t_tuple| 	 17
 	void

The following builtin table rows are ambiguous:

  • class,
  • object,
  • enum,
  • enumvalue

because no builtin classes, interfaces, enums are provided
to date; builtin support is offered for such user-defined
kinds of types.

The type() column looks out of place as long as the
suggested idioms (:help type()) for using this function
avoid comparison with magic numbers. Reporting these magic
numbers in examples is of dubious value.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407825663@github.com>

Aliaksei Budavei

unread,
Nov 1, 2025, 7:26:27 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

>  
-	:class MyTemplate<Targ>
-	:var mine: MyTemplate<number>
-	:var mine: MyTemplate<string>
+	vim9script
+	type Ln = list<number>
+	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

My mistake.

I wonder, where does interface<Shape> lurk?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407825741@github.com>

Aliaksei Budavei

unread,
Nov 1, 2025, 7:26:50 PM (10 days ago) Nov 1
to vim/vim, Subscribed

@zzzyxwvut commented on this pull request.


In runtime/doc/vim9.txt:

> +The syntax of a type cast is:  "<" {type} ">".  White space isn't allowed
+either after the "<" or before the ">" (to avoid them being confused with
+smaller-than and greater-than operators).  Examples: >vim9
+
+	vim9cmd echo [1, <number g:num]   # E1104: Missing >
+	vim9cmd echo [1, <number >g:num]  # E1068: No white space allowed...
+	vim9cmd echo [1, < number>g:num]  # E15: Invalid expression ...

Do we really need to reaffirm the reader that both angle
brackets are required?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3407825850@github.com>

Peter Kenny

unread,
Nov 2, 2025, 1:49:36 AM (10 days ago) Nov 2
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +The following builtin types, each with its corresponding |v:t_TYPE| and |type()|
+value, are supported:
+
+	builtin type			|v:t_TYPE|	|type()|
+	--------------------------	------------	------
+	number				|v:t_number|	  0
+	string				|v:t_string|	  1
+	func				|v:t_func|	  2
+	func: {type}			|v:t_func|	  2
+	func({type}, ...)		|v:t_func|	  2
+	func({type}, ...): {type}	|v:t_func|	  2
+	list<{type}>			|v:t_list|	  3
+	dict<{type}>			|v:t_dict|	  4
+	float				|v:t_float|	  5
+	bool				|v:t_bool|	  6
+	none				|v:t_none|	  7
+	job				|v:t_job|	  8
+	channel				|v:t_channel|	  9
+	blob				|v:t_blob|	 10
+	class				|v:t_class|	 12
+	object				|v:t_object|	 13
+	typealias			|v:t_typealias|	 14
+	enum				|v:t_enum|	 15
+	enumvalue			|v:t_enumvalue|	 16
+	tuple<{type}>			|v:t_tuple|	 17
+	tuple<{type}, {type}, ...>	|v:t_tuple| 	 17
+	tuple<...list<{type}>>		|v:t_tuple| 	 17
+	tuple<{type}, ...list<{type}>>	|v:t_tuple| 	 17
 	void

I agree with your point on the type() column, which is consistent with the help at *type()*. Yes, it is of debatable value. It's gone.

The builtin point I think is better addressed by not using the word. I'd made no connection to that subtlety. However, providing the complete list of types, especially when all are discussed subsequently in Section 4, makes sense.

Here's a revision, which eliminates the "builtin" potential ambiguity, heralds all the types discussed in Section 4, and removes the type() column:

image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3408181931@github.com>

Peter Kenny

unread,
Nov 2, 2025, 2:00:13 AM (10 days ago) Nov 2
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +The difference is demonstrated in the following example.  In function "NTC",
+Vim infers the expression type "[1, b:two]" as list<any>, then verifies
+whether it can be assigned to the list<number> return type.  In function "TC",
+the type cast means Vim first checks whether "b:two" is a <number> type: >vim9
+
+	vim9script
+	b:two = '2'
+	const NTC: func = (): list<number> => {
+	    return [1, b:two]
+	    }
+	disassemble NTC  # 3 CHECKTYPE list<number> stack [-1]
+	try
+	    NTC()
+	catch
+	    echo v:exception .. "\n\n"  # expected list<number> but...
+	endtry
+	const TC: func = (): list<number> => {
+	    return [1, <number>b:two]
+	    }

Yep. Good call out. Changing to:

The difference is demonstrated in the following example.  With funcref variable
"NTC", Vim infers the expression type "[1, b:two]" as list<any>, then verifies
whether it can be assigned to the list<number> return type.  With funcref
variable "TC", the type cast means Vim first checks whether "b:two" is a
<number> type: >vim9


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3408184082@github.com>

Peter Kenny

unread,
Nov 2, 2025, 2:33:52 AM (10 days ago) Nov 2
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +	enum Quad
+	    Square('four', 'only'),
+	    Rhombus('opposite', 'no')
+	    var eq: string
+	    var ra: string
+	    def About(): string
+	        return $"\nA {this.name} has " ..
+	               $"{this.eq} equal sides and {this.ra} right angles\n\n"
+	    enddef
+	endenum

I'd not noticed the builtin-object-methods. Nice. I presume you were only pointing out the alternative? What's there now feels more obvious (in a simple explanation of the enum type) than:

	    def string(): string
...
	echo myQuad

Perhaps a Note after the example could be added noting string() is an alternative, referencing the builtin-object-methods?


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3408200008@github.com>

Peter Kenny

unread,
Nov 5, 2025, 2:09:58 PM (6 days ago) Nov 5
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +The syntax of a type cast is:  "<" {type} ">".  White space isn't allowed
+either after the "<" or before the ">" (to avoid them being confused with
+smaller-than and greater-than operators).  Examples: >vim9
+
+	vim9cmd echo [1, <number g:num]   # E1104: Missing >
+	vim9cmd echo [1, <number >g:num]  # E1068: No white space allowed...
+	vim9cmd echo [1, < number>g:num]  # E15: Invalid expression ...

This will do (without the example):

						*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.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3423853256@github.com>

Peter Kenny

unread,
Nov 5, 2025, 2:37:50 PM (6 days ago) Nov 5
to vim/vim, Push

@kennypete pushed 1 commit.

  • a5c3957 runtime/doc/vim9.txt - Section 4 updated


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/ecd61dac79169147105e647bed830a5244a3fd13/after/a5c395712465c5f5ad4cb71ac714bebd900073aa@github.com>

Christian Brabandt

unread,
Nov 5, 2025, 3:56:32 PM (6 days ago) Nov 5
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#18610)

What is the status of it now? Sorry I haven't had the time to review this yet, but it seems you did not need me for this, there is already enough going on here :)
But I'll take some time to review the next days.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3493384141@github.com>

Peter Kenny

unread,
Nov 5, 2025, 10:55:09 PM (6 days ago) Nov 5
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

What is the status of it now? Sorry I haven't had the time to review this yet, but it seems you did not need me for this, there is already enough going on here :) But I'll take some time to review the next days.

No worries. I'm almost done checking all the edits resulting from the changes discussed and will commit that tomorrow morning (NZDT) at the latest, so the timing is perfect for a review shortly. Yes, there has been a lot of good feedback, discussion, and updates.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3494831654@github.com>

Peter Kenny

unread,
Nov 6, 2025, 1:05:21 PM (5 days ago) Nov 6
to vim/vim, Push

@kennypete pushed 2 commits.

  • ad71d5d runtime/doc/vim9.txt - Section 4 updated
  • 1e94889 runtime/doc/vim9.txt - Section 4 - feedback fixes

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/a5c395712465c5f5ad4cb71ac714bebd900073aa/after/1e9488922fc577ec34c1cd6ed45c8765e13e5cbc@github.com>

Christian Brabandt

unread,
Nov 6, 2025, 4:21:17 PM (5 days ago) Nov 6
to vim/vim, Subscribed

@chrisbra commented on this pull request.

just 2 minor things I noticed while reviewing. Looks good otherwise.


In runtime/doc/vim9.txt:

>  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
⬇️ Suggested change
-bugs.  For example, in legacy Vim script this echoes '1': >vim
+bugs.  For example, in legacy Vim script this echoes "1": >vim

In runtime/doc/vim9.txt:

>  	echo 123 == '123'
-<	1 ~
-With an accidental space: >
+<
+However, if an unintended space is included, '0' is echoed: >vim
⬇️ Suggested change
-However, if an unintended space is included, '0' is echoed: >vim
+However, if an unintended space is included, "0" is echoed: >vim


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3430553964@github.com>

Peter Kenny

unread,
Nov 7, 2025, 12:36:22 PM (4 days ago) Nov 7
to vim/vim, Push

@kennypete pushed 3 commits.

  • b67bd87 runtime/doc/vim9.txt - Section 4 updated
  • d7af4b3 runtime/doc/vim9.txt - Section 4 - feedback fixes
  • f7b3b56 runtime/doc/vim9.txt - Section 4 - feedback fixes2


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/1e9488922fc577ec34c1cd6ed45c8765e13e5cbc/after/f7b3b56b663f68cd40cd11cfa6c571a908ae2f08@github.com>

Peter Kenny

unread,
Nov 7, 2025, 12:39:15 PM (4 days ago) Nov 7
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  	echo 123 == '123'
-<	1 ~
-With an accidental space: >
+<
+However, if an unintended space is included, '0' is echoed: >vim

It's fixed in the latest commit.


Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3435407355@github.com>

Peter Kenny

unread,
Nov 7, 2025, 12:39:17 PM (4 days ago) Nov 7
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  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

It's fixed in the latest commit.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3435405850@github.com>

errael

unread,
Nov 7, 2025, 1:00:31 PM (4 days ago) Nov 7
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

>  
 The initialization semantics of container variables and specialized variables
-differ. An uninitialized container defaults to an empty container: >
-	var l1: list<string>		    # empty container
-	var l2: list<string> = []	    # empty container
-	var l3: list<string> = 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:

Should it be noted these examples and descriptions use list. The idea is true for any container, but the syntax for little different depending on the container type.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3435508259@github.com>

errael

unread,
Nov 7, 2025, 1:18:53 PM (4 days ago) Nov 7
to vim/vim, Subscribed

@errael commented on this pull request.


In runtime/doc/vim9.txt:

> +    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|_<type>
+predefined values including |null_string|, |null_list|, and |null_job|.
+Primitives do not have a null_<type>.  Typical use cases for null_<type> are:
+  - to clear a variable and release its resources, or
+  - as a default for a parameter in a function definition, see |null-compare|.

This leftover not quite right. Maybe something like:

  • to clear a variable and release its resources, or
  • as a default for a parameter in a function definition,
  • assigned to a container or specialized variable to set it to null for later comparison, see |null-compare|


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3435589958@github.com>

errael

unread,
Nov 7, 2025, 1:27:39 PM (4 days ago) Nov 7
to vim/vim, Subscribed

@errael commented on this pull request.

A few minor innacuracies.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3435632546@github.com>

Peter Kenny

unread,
Nov 8, 2025, 12:58:19 AM (4 days ago) Nov 8
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

> +    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|_<type>
+predefined values including |null_string|, |null_list|, and |null_job|.
+Primitives do not have a null_<type>.  Typical use cases for null_<type> are:
+  - to clear a variable and release its resources, or
+  - as a default for a parameter in a function definition, see |null-compare|.

That's a good call out. Given the improvements to the *null-compare* passage, it means the second bullet does not provide the promised content any more. There is an example relevant to the second bullet at *null_blob*. So, I'll extend what you have suggested, which looks good, to reference it too.


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3437615568@github.com>

Peter Kenny

unread,
Nov 8, 2025, 9:55:50 PM (3 days ago) Nov 8
to vim/vim, Subscribed

@kennypete commented on this pull request.


In runtime/doc/vim9.txt:

>  
 The initialization semantics of container variables and specialized variables
-differ. An uninitialized container defaults to an empty container: >
-	var l1: list<string>		    # empty container
-	var l2: list<string> = []	    # empty container
-	var l3: list<string> = 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:

On reading it again, there is a bit more to adjust following that line, "differ. For containers:".  The use of "is not null" is unhelpful in the bullets (and in a few other places in the *null-variables* passage, which I'll fix). The point relates to ==, not is/isnot, so it’s best to clarify that.

It should read:

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_<type> defaults to empty and equals `null`.

These changes, including using null_<type> (rather than null_list) in the third bullet, address your point.


An aside...

If we also had an examples/tutorial facility (though that's for another day), a much longer example could cover it all, e.g., something like:

vim9script

var sn: string = null_string
var su: string
var si: string = ''
var bn: blob = null_blob
var bu: blob
var bi: blob = 0z
var ln: list<any> = null_list
var lu: list<any>
var li: list<any> = []
var dn: dict<any> = null_dict
var du: dict<any>
var di: dict<any> = {}
var tn: tuple<any> = null_tuple
var tu: tuple<any>
var ti: tuple<any> = ()

def C<T>(arg1: T, arg2: string): string
  return $"{arg2}\t {empty(arg1) ? true : false}"
enddef

echo "\t\tempty()\t== null\tis null"
echo "\t\t-------\t-------\t-------"

echo "null_<type>"
echo C<string>(sn, "  null_string") .. $"\t {sn == null}\t {sn is null}"
echo C<blob>(bn, "  null_blob  ") .. $"\t {bn == null}\t {bn is null}"
echo C<list<any>>(ln, "  null_list  ") .. $"\t {ln == null}\t {ln is null}"
echo C<dict<any>>(dn, "  null_dict  ") .. $"\t {dn == null}\t {dn is null}"
echo C<tuple<any>>(tn, "  null_tuple ") .. $"\t {tn == null}\t {tn is null}"

echo "\nUninitialized:"
echo C<string>(su, "  string") .. $"\t {su == null}\t {su is null}"
echo C<blob>(bu, "  blob  ") .. $"\t {bu == null}\t {bu is null}"
echo C<list<any>>(lu, "  list  ") .. $"\t {lu == null}\t {lu is null}"
echo C<dict<any>>(du, "  dict  ") .. $"\t {du == null}\t {du is null}"
echo C<tuple<any>>(tu, "  tuple ") .. $"\t {tu == null}\t {tu is null}"

echo "\nInitialized:"
echo C<string>(si, "  '' string") .. $"\t {si == null}\t {si is null}"
echo C<blob>(bi, "  0z blob  ") .. $"\t {bi == null}\t {bi is null}"
echo C<list<any>>(li, "  [] list  ") .. $"\t {li == null}\t {li is null}"
echo C<dict<any>>(di, "  {} dict  ") .. $"\t {di == null}\t {di is null}"
echo C<tuple<any>>(ti, "  () tuple ") .. $"\t {ti == null}\t {ti is null}"

... which also highlights the odd one out:
image.png (view on web)


Reply to this email directly, view it on GitHub, or unsubscribe.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/review/3439311546@github.com>

Peter Kenny

unread,
Nov 8, 2025, 10:04:01 PM (3 days ago) Nov 8
to vim/vim, Push

@kennypete pushed 3 commits.

  • 0b808be runtime/doc/vim9.txt - Section 4 updated
  • 29006e6 runtime/doc/vim9.txt - Section 4 - feedback fixes
  • a5be3c5 runtime/doc/vim9.txt - Section 4 - feedback fixes2


View it on GitHub or unsubscribe.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/f7b3b56b663f68cd40cd11cfa6c571a908ae2f08/after/a5be3c50f79620668c5ee573796578e9dc46db27@github.com>

Peter Kenny

unread,
Nov 8, 2025, 10:24:39 PM (3 days ago) Nov 8
to vim/vim, Push

@kennypete pushed 1 commit.

  • f418e33 runtime/doc/vim9.txt - Section 4 - feedback fixes3

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/a5be3c50f79620668c5ee573796578e9dc46db27/after/f418e333f1bb190e0737b37905c32b76b9cb1135@github.com>

Peter Kenny

unread,
Nov 9, 2025, 12:49:43 AM (3 days ago) Nov 9
to vim/vim, Push

@kennypete pushed 1 commit.

  • 4bdf942 runtime/doc/vim9.txt - Section 4 - 9 Nov & misc

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/before/f418e333f1bb190e0737b37905c32b76b9cb1135/after/4bdf942d546266cc6774fcad89d4cbf4c8b31b8a@github.com>

Peter Kenny

unread,
Nov 10, 2025, 12:42:21 PM (yesterday) Nov 10
to vim/vim, Subscribed
kennypete left a comment (vim/vim#18610)

just 2 minor things I noticed while reviewing. Looks good otherwise.

Those are 2 things are fixed. A few others too from last-minute call outs.

It should be good to go now. Anything else in this Section 4 others can pick up separately later, if necessary, I think. An uplift update of this size will naturally have something that could be improved, and it would be good to get on to doing Section 3.


Reply to this email directly, view it on GitHub.
You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3513105042@github.com>

Christian Brabandt

unread,
Nov 10, 2025, 3:28:58 PM (yesterday) Nov 10
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#18610)

There is a broken Vim help reference to interface. I'll fix it while merging


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/c3513773242@github.com>

Christian Brabandt

unread,
Nov 10, 2025, 3:30:30 PM (yesterday) Nov 10
to vim/vim, Subscribed

Closed #18610 via 54cc820.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/pull/18610/issue_event/20846304177@github.com>

Reply all
Reply to author
Forward
0 new messages