changeset 34017:681e2c008f83

runtime(doc): Add variable categories and null related documentation(#13750) Commit: https://github.com/vim/vim/commit/cea3dac76e42c9a33dccbd2f10ef011f0be5c292 Author: errael <errael@raelity.com> Date: Mon Dec 25 01:31:23 2023 -0800 runtime(doc): Add variable categories and null related documentation(https://github.com/vim/vim/issues/13750) Signed-off-by: Ernie Rael <errael@raelity.com> Signed-off-by: Christian Brabandt <cb@256bit.org>
author Christian Brabandt <cb@256bit.org>
date Mon, 25 Dec 2023 10:45:03 +0100
parents 34f6f3678cae
children d81556766132
files runtime/doc/tags runtime/doc/vim9.txt
diffstat 2 files changed, 160 insertions(+), 3 deletions(-) [+]
line wrap: on
line diff
--- a/runtime/doc/tags
+++ b/runtime/doc/tags
@@ -9082,7 +9082,11 @@ notepad	gui_w32.txt	/*notepad*
 nr2char()	builtin.txt	/*nr2char()*
 nroff.vim	syntax.txt	/*nroff.vim*
 null	vim9.txt	/*null*
+null-anomalies	vim9.txt	/*null-anomalies*
+null-compare	vim9.txt	/*null-compare*
+null-details	vim9.txt	/*null-details*
 null-variable	eval.txt	/*null-variable*
+null-variables	vim9.txt	/*null-variables*
 null_blob	vim9.txt	/*null_blob*
 null_channel	vim9.txt	/*null_channel*
 null_class	vim9.txt	/*null_class*
@@ -10945,6 +10949,7 @@ val-variable	eval.txt	/*val-variable*
 valgrind	debug.txt	/*valgrind*
 values()	builtin.txt	/*values()*
 var-functions	usr_41.txt	/*var-functions*
+variable-categories	vim9.txt	/*variable-categories*
 variable-scope	eval.txt	/*variable-scope*
 variable-types	vim9.txt	/*variable-types*
 variables	eval.txt	/*variables*
--- a/runtime/doc/vim9.txt
+++ b/runtime/doc/vim9.txt
@@ -1,4 +1,4 @@
-*vim9.txt*	For Vim version 9.0.  Last change: 2023 Dec 09
+*vim9.txt*	For Vim version 9.0.  Last change: 2023 Dec 24
 
 
 		  VIM REFERENCE MANUAL	  by Bram Moolenaar
@@ -1055,8 +1055,11 @@ variable, since they cannot be deleted w
 
 The values can also be useful as the default value for an argument: >
 	def MyFunc(b: blob = null_blob)
-	   if b == null_blob
-	      # b argument was not given
+	    # Note: compare against null, not null_blob,
+	    #       to distinguish the default value from an empty blob.
+	    if b == null
+	        # b argument was not given
+See |null-compare| for more information about testing against null.
 
 It is possible to compare `null`  with any value, this will not give a type
 error.  However, comparing `null` with a number, float or bool will always
@@ -1698,6 +1701,155 @@ argument type checking: >
 Types are checked for most builtin functions to make it easier to spot
 mistakes.
 
+Categories of variables, defaults and null handling ~
+				*variable-categories* *null-variables*
+There are categories of variables:
+	primitive	number, float, boolean
+	container	string, blob, list, dict
+	specialized	function, job, channel, user-defined-object
+
+When declaring a variable without an initializer, an explicit type must be
+provided. Each category has different default initialization semantics. Here's
+an example for each category: >
+	var num: number		# primitives default to a 0 equivalent
+	var cont: list<string>	# containers default to an empty container
+	var spec: job		# specialized variables default to null
+<
+Vim does not have a familiar null value; it has various null_<type> predefined
+values, for example |null_string|, |null_list|, |null_job|. Primitives do not
+have a null_<type>. The typical use cases for null_<type> are:
+- to `clear a variable` and release its resources;
+- as a `default for a parameter` in a function definition, see |null-compare|.
+
+For a specialized variable, like `job`, null_<type> is used to clear the
+resources. For a container variable, resources can also be cleared by
+assigning an empty container to the variable. For example: >
+	var j: job = job_start(...)
+	# ... job does its work
+	j = null_job	# clear the variable and release the job's resources
+
+	var l: list<any>
+	# ... add lots of stuff to list
+	l = []  # clear the variable and release container resources
+Using the empty container, rather than null_<type>, to clear a container
+variable may avoid null complications as described in |null-anomalies|.
+
+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: >
+	var j1: job
+	var j2: job = null_job
+	var j3 = null_job
+
+When a list or dict is declared, if the item type is not specified and can not
+be inferred, then the type is "any": >
+	var d1 = {}		# type is "dict<any>"
+	var d2 = null_dict	# type is "dict<any>"
+
+Declaring a function, see |vim9-func-declaration|, is particularly unique.
+
+						*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
+	enddef
+	F()		# output: "null"
+	F(null_list)	# output: "null"
+	F([])		# output: "not null, empty"
+	F([''])		# output: "not null, not empty"
+The above function takes a `list of strings` and reports on it.
+Change the above function signature to accept different types of arguments: >
+	def F(arg: list<any> = null_list)   # any type of list
+	def F(arg: any = null)		    # any type
+<
+In the above example, where the goal is to distinguish a null list from an
+empty list, comparing against `null` instead of `null_list` is the correct
+choice. The basic reason is because "null_list == null" and "[] != null".
+Comparing to `null_list` fails since "[] == null_list". In the following section
+there are details about comparison results.
+
+					*null-details* *null-anomalies*
+This section describes issues about using null and null_<type>; included below
+are the enumerated results of null comparisons. In some cases, if familiar
+with vim9 null semantics, the programmer may chose to use null_<type> in
+comparisons and/or other situations.
+
+Elsewhere in the documentation it says:
+	Quite often a null value is handled the same as an
+	empty value, but not always
+Here's an example: >
+	vim9script
+	var s1: list<string>
+	var s2: list<string> = null_list
+	echo s1		    # output: "[]"
+	echo s2		    # output: "[]"
+	
+	echo s1 + ['a']     # output: "['a']"
+	echo s2 + ['a']     # output: "['a']"
+	
+	echo s1->add('a')   # output: "['a']"
+	echo s2->add('a')   # E1130: Can not add to null list
+<
+Two values equal to a null_<type> are not necessarily equal to each other: >
+	vim9script
+	echo {} == null_dict      # true
+	echo null_dict == null    # true
+	echo {} == null           # false
+<
+Unlike the other containers, an uninitialized string is equal to null. The
+'is' operator can be used to determine if it is a null_string: >
+	vim9script
+	var s1: string
+	var s2 = null_string
+	echo s1 == null		# true - this is unexpected
+	echo s2 == null		# true
+	echo s2 is null_string	# true
+
+	var b1: blob
+	var b2 = null_blob
+	echo b1 == null		# false
+	echo b2 == null		# true
+<
+Any variable initialized to the null_<type> is equal to the null_<type> and is
+also equal to null. For example: >
+	vim9script
+	var x = null_blob
+	echo x == null_blob	# true
+	echo x == null		# true
+<
+An uninitialized variable is usually equal to null; it depends on its type:
+	var s: string		s == null
+	var b: blob		b != null   ***
+	var l: list<any>	l != null   ***
+	var d: dict<any>	d != null   ***
+	var f: func		f == null
+	var j: job		j == null
+	var c: channel		c == null
+	var o: Class		o == null
+
+A variable initialized to empty equals null_<type>; but not null:
+	var s2: string = ""	  == null_string	!= null
+	var b2: blob = 0z	  == null_blob		!= null
+	var l2: list<any> = []	  == null_list		!= null
+	var d2: dict<any> = {}	  == null_dict		!= null
+
+NOTE: the specialized variables, like job, default to null value and have no
+corresponding empty value.
+
 ==============================================================================
 
 5. Namespace, Import and Export