[vim/vim] Vim9 script truthiness issues (Issue #19173)

17 views
Skip to first unread message

Peter Kenny

unread,
Jan 13, 2026, 2:32:49 PMJan 13
to vim/vim, Subscribed
kennypete created an issue (vim/vim#19173)

I'm most of the way through updating the vim9.txt help, with only the last few subsections of Section 2 to go now, and have gotten stuck on this truthiness table in the "For the "??" operator" paragraph. It reads:

	type		truthy when ~
	bool		true, v:true or 1
	number		non-zero
	float		non-zero
	string		non-empty
	blob		non-empty
	list		non-empty (different from JavaScript)
	tuple		non-empty (different from JavaScript)
	dictionary	non-empty (different from JavaScript)
	func		when there is a function name
	special		true or v:true
	job			when not NULL
	channel		when not NULL
	class		when not NULL
	object		when not NULL (TODO: when isTrue() returns true)

The following types are all correct as documented: bool, number, float, string, blob, list, tuple, dictionary, func, job, and channel. Issues are with these:

  • class: "when not NULL" is incorrect because this type is never truthy. Trying to use a class to test for truthiness gives E1421: Class "Class" cannot be used as a value. The exception is null_class, though it is falsy anyhow (:vim9cmd echo null_class ?? 'falsy'). I think it should be removed from the list and moved to the notes covering the types that have no possible truthiness.
  • object: "when not NULL" is incorrect because it appears that, currently at least, all objects are falsy. So, this is either a documentation mistake requiring correction or its a bug. (Also, should, "(TODO: when isTrue() returns true)" be removed?)
  • special: This is not a type per se. There is the none type (v:t_none), which is falsy only, though. So, I think it would be better to remove special and instead include none in a note covering the types which have no possible truthiness.

For completeness, these should also either be included in the list or covered in my proposed note:

  • enum: This is the same as class, never truthy, gives E1421 (though without null_enum existing it is slightly different to class).
  • enumvalue: An enum value, whether initialised or not, is falsy. Whether that's intentional, and an initialised enum should be truthy, I don't know, though with it currently "never truthy", that aligns with the similar object type.
  • typealias: Gives E1421, so should just be added to the "never truthy" note.

Note/Particularly: There is a distinction between:

  • Types that can't be used as values at all (class, enum, typealias) ... E1421
  • Types where values are always falsy even when not null (object, enumvalue) ... are these special cases or a bug?

The following script illustrates these points.

vim9script

def Ftruthy(t: any, f: any): list<any>
    return [t, !t ?? 'truthy', f, f ?? 'falsy']
enddef

# These working as documented
# ---------------------------
echo 'Primitives, like number (type 0), work as documented:'
echo Ftruthy(9, 0)
echo '	'
echo 'Collections, like list (type 3), work as documented:'
echo Ftruthy([9], null_list)
echo '	'
echo 'Funcref (type 2) works as documented:'
var F = (x) => x
echo Ftruthy(F, null_function)
echo '	'
echo 'Job (type 8) works as documented:'
var Job = job_start(['echo', 'test'])
echo Ftruthy(Job, null_job)
Job = null_job

# Class and object
# ----------------
echo '	'
echo 'Class (type 12) gives E1421: '
class Class
    var x: number
endclass
try
    echo Ftruthy(Class, null_class)
catch
    echo v:exception  # E1421: Class "Class" cannot be used as a value
finally
    echo '	'
    echo 'Object (type 13) is never truthy, including when not null: '
    var o1 = Class.new(5)
    var o2 = null_object
    echo Ftruthy(o1, o2)
endtry

# Enum and enumvalue
# ------------------
echo '	'
echo 'Enum (type 15) gives E1421: '
enum Enum
    Placeholder
endenum
try
    echo Ftruthy(Enum, null_class)  # There is no null_enum...using null_class
catch
    echo v:exception  # E1421: Enum "Enum" cannot be used as a value
finally
    echo '	'
    echo 'Enum value (type 16) is never truthy, including when not null: '
    var e1 = Enum.Placeholder
    var e2: Enum  # uninitialized enum value == null (echo e2 == null ... true)
    echo Ftruthy(e1, e2)
endtry

And the output:
image.png (view on web)


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

Peter Kenny

unread,
Jan 18, 2026, 2:39:57 PMJan 18
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

[Edits: fixed for my mistake surrounding E1405/E1421, which are only given when using Class/Enum as a value; ?? does not error with them, so the script to illustrate the point has been adjusted accordingly.]

My key question remains, i.e., Should types 12 to 16 be truthy when not null?; @chrisbra - perhaps you know the answer to this? My presumption is that it is unintentional/an oversight, so a bug, especially given the documentation currently promises that non-null Class and Object variables should be truthy, "when not NULL".


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3765660914@github.com>

Christian Brabandt

unread,
Jan 18, 2026, 3:48:19 PMJan 18
to vim/vim, Subscribed
chrisbra left a comment (vim/vim#19173)

I would defer to @yegappan for this one please


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3765729094@github.com>

Yegappan Lakshmanan

unread,
Jan 19, 2026, 12:26:51 AMJan 19
to vim/vim, Subscribed
yegappan left a comment (vim/vim#19173)

@kennypete A class, enum, or typealias cannot be used as a value, so the help text should be updated to reflect that. I'll raise a PR to ensure we return true for non-null objects and enum values.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3766463868@github.com>

Peter Kenny

unread,
Jan 19, 2026, 1:47:23 AMJan 19
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

@kennypete A class, enum, or typealias cannot be used as a value, so the help text should be updated to reflect that. I'll raise a PR to ensure we return true for non-null objects and enum values.

Thanks @yegappan - I presumed object and enumvalue were/are wrong, so a PR for them sounds good.

Regarding class, enum, and typealias, though, initially they tripped me up because it's common to get, "cannot be used as a value", errors. Thing is though, as my script, above, shows, they can be tested, without error, with ?? in a script-local scope. In that case, they are always falsy, regardless of whether they are null. Focusing on those only, and showing ! too:

vim9script

echo '---null_class---'
echo 'null_class'
echo null_class ?? 'unknown class'  # echos 'unknown class', as expected

echo '---class---'
class MyClass
endclass
echo MyClass ?? 'unknown class'  # echos 'unknown class', but it's not null
echo !MyClass  # echos true (falsy), which does not make sense?

echo '---typealias---'
type LB = list<bool>
echo LB ?? 'unknown typealias'  # echos 'unknown typealias', but it's not null
echo !LB  # echos true (falsy), which does not make sense?

echo '---enum---'
enum MyEnum
endenum
echo MyEnum ?? 'unknown enum'  # echos 'unknown enum', but it's not null
echo !MyEnum  # echos true (falsy), which does not make sense?

This script shows that these types can be tested with ?? and ! operators without error. So, they are usable as values in boolean script-local contexts, yet they are always falsy, even when not null. Given the general rule is "truthy when neither empty nor null", shouldn't MyClass, LB, and MyEnum be truthy in this context?


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3766717508@github.com>

Yegappan Lakshmanan

unread,
Jan 19, 2026, 1:44:34 PMJan 19
to vim/vim, Subscribed
yegappan left a comment (vim/vim#19173)

@kennypete A class, enum, or typealias cannot be used as a value, so the help text should be updated to reflect that. I'll raise a PR to ensure we return true for non-null objects and enum values.

Thanks @yegappan - I presumed object and enumvalue were/are wrong, so a PR for them sounds good.

Regarding class, enum, and typealias, though, initially they tripped me up because it's common to get, "cannot be used as a value", errors. Thing is though, as my script, above, shows, they can be tested, without error, with ?? in a script-local scope. In that case, they are always falsy, regardless of whether they are null. Focusing on those only, and showing ! too:

I have opened the PR #19216 to address this. Now class, enum
and typealiases cannot be used with the falsy operator.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3769686907@github.com>

Peter Kenny

unread,
Jan 19, 2026, 2:03:14 PMJan 19
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

I have opened the PR #19216 to address this. Now class, enum and typealiases cannot be used with the falsy operator.

Thanks, that feels like the right call, with the minor backwards incompatibility issue if anyone actually has used ?? or ! with a class, enum, or typealias in practice, which feels improbable.

PR #19216, and one to ensure non-null object and enumvalue variables are truthy, will make everything consistent.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3769734553@github.com>

Christian Brabandt

unread,
Jan 20, 2026, 2:49:56 PMJan 20
to vim/vim, Subscribed

Closed #19173 as completed via a7d1954.


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/issue/19173/issue_event/22170650095@github.com>

Peter Kenny

unread,
Jan 20, 2026, 8:16:42 PMJan 20
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

Hi @yegappan, I checked out 9.1.2096 and 9.1.2101 and found the former fixes object/enumvalue, which are now truthy when not null, but the latter is not only erroring on class/enum/typealias (which is right) but it is also being evaluated when used with the falsy operator. A script and output to illustrate:

vim9script
echo v:versionlong  # 9012101

class C
endclass
echo C ?? false
image.png (view on web)
It's similar for enum and typealias too.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3775672352@github.com>

Yegappan Lakshmanan

unread,
Jan 22, 2026, 1:23:08 AMJan 22
to vim/vim, Subscribed
yegappan left a comment (vim/vim#19173)

Hi @yegappan, I checked out 9.1.2096 and 9.1.2101 and found the former fixes object/enumvalue, which are now truthy when not null, but the latter is not only erroring on class/enum/typealias (which is right) but it is also being evaluated when used with the falsy operator. A script and output to illustrate:

vim9script
echo v:versionlong  # 9012101

class C
endclass
echo C ?? false

It's similar for enum and typealias too.

I have opened the PR #19238 to abort the expression evaluation when a class or enum or a type alias is used as a value.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3782696790@github.com>

Peter Kenny

unread,
Jan 22, 2026, 2:50:27 AMJan 22
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

I have opened the PR #19238 to abort the expression evaluation when a class or enum or a type alias is used as a value.

Thanks, that should close the loose end.

Incidentally, now that class can't be used as a value in any context (E1405), does null_class serve any purpose? Before patch 9.1.2101, it had one theoretical use case (that is, if a non-null class had been "fixed" to be evaluated as truthy, null_class would have been falsy). I can't think what it would/could be used for now, though.

A similar question does not apply to the other two because there is neither null_enum nor null_typealias (not that it would make sense anyway).


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3783016633@github.com>

Yegappan Lakshmanan

unread,
Jan 22, 2026, 10:47:57 AMJan 22
to vim/vim, Subscribed
yegappan left a comment (vim/vim#19173)

I have opened the PR #19238 to abort the expression evaluation when a class or enum or a type alias is used as a value.

Thanks, that should close the loose end.

Incidentally, now that class can't be used as a value in any context (E1405), does null_class serve any purpose? Before patch 9.1.2101, it had one theoretical use case (that is, if a non-null class had been "fixed" to be evaluated as truthy, null_class would have been falsy). I can't think what it would/could be used for now, though.

A similar question does not apply to the other two because there is neither null_enum nor null_typealias (not that it would make sense anyway).

The null_class is useful for testing the Vim9 class functionality with a null pointer for the class.


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3785128262@github.com>

Peter Kenny

unread,
Jan 24, 2026, 2:18:22 AMJan 24
to vim/vim, Subscribed
kennypete left a comment (vim/vim#19173)

The null_class is useful for testing the Vim9 class functionality with a null pointer for the class.

Sorry, this will be my last query about this...

I grepped the C source for null_class usage and found this in typval.c (line 1789):

// TODO: null_class handling
// case VAR_CLASS: return tv->vval.v_class == NULL;

That commented null comparison handling would now be contradictory given null_class == {anything} gives E1405, so the comment there could be updated.

The only actual usage appears to be instanceof(null_object, null_class). Testing shows null_object is only an instance of null_class (and never an instance of an actual class), making this equivalent to obj == null_object, i.e., potentially redundant.

Unlike other null_* values, which serve clear purposes (uninitialized containers, etc.), null_class appears to exist only so testing can verify it produces errors, so it is circular. Is there practical null pointer testing I'm missing, or was this planned, left incomplete, and now unnecessary?

There is also testdir/test_vim9_disassemble.vim, which has var nc = null_class, showing null_class had been expected to be used as a value? It's also problematic because now the compilation will succeed, and disassembly shows likewise, but at runtime it's E1405, e.g.:

image.png (view on web)


Reply to this email directly, view it on GitHub.

You are receiving this because you are subscribed to this thread.Message ID: <vim/vim/issues/19173/3794040445@github.com>

Reply all
Reply to author
Forward
0 new messages