Null Delimited with Octothorpes and Null Propagation Returns "Null" (3 Viewers)

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
Perhaps this is new, or just new to me, but I just learned that a string that concatenates a Null Variant variable between octothorpes using Null propagation (by use of the + operator) does not return Null but rather the string "Null" (without the quotation marks).

This can be handy but I just can't figure out why that would be. An hour with Google was fruitless.

Here's the function:

Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
    
    varTest = Null
    varReturn = "#" + varTest + "#"
    
    TestNullVariant = varReturn
End Function
 

Josef P.

Well-known member
Local time
Today, 11:18
Joined
Feb 2, 2023
Messages
924
TestNullVariant should return Null (not the string Null).

Simple test:
Code:
Dim x As Variant
x = TestNullVariant()
If IsNull(x) Then
   Debug.Print "x is null .. as expected"
Else
   Debug.Print "x is not null .. ???"
End If
 

GPGeorge

George Hepworth
Local time
Today, 02:18
Joined
Nov 25, 2004
Messages
2,164
Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
    
    varTest = Null
    varReturn = "#" + varTest + "#"
    
    TestNullVariant = varReturn
    Debug.Print TestNullVariant
    Debug.Print IsNull(TestNullVariant)
    
End Function

Immediate Window Output:

Code:
Null
True
 

Gasman

Enthusiastic Amateur
Local time
Today, 10:18
Joined
Sep 21, 2011
Messages
14,764
I do not think so?, as using len() one still gets Null not the length of a string as Null

Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
    
    varTest = Null
    Debug.Print Len(varTest)
    varReturn = "#" + varTest + "#"
    Debug.Print Len(varReturn)
    TestNullVariant = varReturn
End Function
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 05:18
Joined
May 21, 2018
Messages
8,755
I do not think so, simply test your own function.
Code:
Public Sub Test()
  Debug.Print "Variable type: " & vartype(TestNullVariant()) & " and is null: " & IsNull(TestNullVariant)
  'vartype of 1 = vbnull
End Sub
This returns
Code:
variable type: 1 and is null: True
Both show it is real Null not a string Null
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
I've been tinkering a bit. If concatenated with &, Null returns; if concatenated with +, "Null" returns.

Expanding the original function a bit and adding a test function (with the Immediate pane output commented by line) illustrates my observation.

What's interesting is that the test function evaluates the parameter as Null AND prints/returns "Null". Curiouser and curiouser.

Here are the revised functions:

Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
 
    varTest = Null                                  'Output to Immediate pane:
    varReturn = "#" + varTest + "#"
    Debug.Print varReturn                           'Null [String]
    Debug.Print "varReturn = >" + varReturn + "<"   'Null [String]
    Debug.Print "varReturn = >" & varReturn & "<"   'varReturn = ><
 
    TestNullVariant = varReturn                     'Null [String]
End Function    'TestNullVariant()

Function TestTheTest(varThis As Variant) As Variant
    If (IsNull(varThis)) Then                       'Output to Immediate pane:
        Debug.Print "varThis is Null."              'varThis is Null.
    Else
        Debug.Print "varThis = >" & varThis & "<"   '[no output]
    End If
    Debug.Print varThis                             'Null [String]
    TestTheTest = varThis                           'Null [String]
End Function    'TestTheTest()

The call is

Code:
TestTheTest(TestNullVariant)
 

Josef P.

Well-known member
Local time
Today, 11:18
Joined
Feb 2, 2023
Messages
924
Are you possibly interpreting the output via Debug.Print as a return value?
Debug.Print always creates a string and converts Null to the string Null. A date is also displayed as a formatted date string.
However, this is only the representation of the value as a string.
 

theDBguy

I’m here to help
Staff member
Local time
Today, 02:18
Joined
Oct 29, 2018
Messages
21,709
I've been tinkering a bit. If concatenated with &, Null returns; if concatenated with +, "Null" returns.

Expanding the original function a bit and adding a test function (with the Immediate pane output commented by line) illustrates my observation.

What's interesting is that the test function evaluates the parameter as Null AND prints/returns "Null". Curiouser and curiouser.

Here are the revised functions:

Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant

    varTest = Null                                  'Output to Immediate pane:
    varReturn = "#" + varTest + "#"
    Debug.Print varReturn                           'Null [String]
    Debug.Print "varReturn = >" + varReturn + "<"   'Null [String]
    Debug.Print "varReturn = >" & varReturn & "<"   'varReturn = ><

    TestNullVariant = varReturn                     'Null [String]
End Function    'TestNullVariant()

Function TestTheTest(varThis As Variant) As Variant
    If (IsNull(varThis)) Then                       'Output to Immediate pane:
        Debug.Print "varThis is Null."              'varThis is Null.
    Else
        Debug.Print "varThis = >" & varThis & "<"   '[no output]
    End If
    Debug.Print varThis                             'Null [String]
    TestTheTest = varThis                           'Null [String]
End Function    'TestTheTest()

The call is

Code:
TestTheTest(TestNullVariant)
Here's my results...
1720036681483.png
 

MajP

You've got your good things, and you've got mine.
Local time
Today, 05:18
Joined
May 21, 2018
Messages
8,755
I've been tinkering a bit. If concatenated with &, Null returns; if concatenated with +, "Null" returns.
That is just a convention of the Immediate window and proves nothing. Push the same results to a textbox instead. You will get a blank row for Null not a visual depiction of Null.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 04:18
Joined
Feb 28, 2001
Messages
27,697
The problem is that you are using octothorpes in a context where they are "datatype hints" and thus you are formatting "# null #" which will become a null DATE. That's why the octothorpes disappear.
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
   
    varTest = Null
    varReturn = "#" + varTest + "#"
   
    TestNullVariant = varReturn
    Debug.Print TestNullVariant
    Debug.Print IsNull(TestNullVariant)
   
End Function

Immediate Window Output:

Code:
Null
True
George, this illustrates and confirms the behavior of my "TestTheTest" function, which is that the return both evaluates as Null and prints the string.
 

GPGeorge

George Hepworth
Local time
Today, 02:18
Joined
Nov 25, 2004
Messages
2,164
I think
George, this illustrates and confirms the behavior of my "TestTheTest" function, which is that the return both evaluates as Null and prints the string.
I think what it prints is that the variant evaluates to Null, not that it evaluates to a string of "Null". Further testing, such as getting the Len() of the variant should confirm that.
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
Are you possibly interpreting the output via Debug.Print as a return value?
Debug.Print always creates a string and converts Null to the string Null. A date is also displayed as a formatted date string.
However, this is only the representation of the value as a string.
Actually, I've been tinkering further and this (inconsistent output to memory and the Immediate window) seems exactly to be what is occurring.

I tested a variety of means to obtain or assign the string output, without success. Given the input I described, the VBE, as compiler / command interpreter / shell consistently outputs Null to memory and the string "Null" to the Immediate window. In all other cases of Null, the VBE prints nothing to the Immediate window.

So, it turns out the syntax I described doesn't return the string "Null" after all, it just tricks the VBE into outputting it to the Immediate window. I can't imagine a reason for such inconsistent output, and many reasons to avoid it, so I presume it is unintentional even if an arcane explanation exists.
 

theDBguy

I’m here to help
Staff member
Local time
Today, 02:18
Joined
Oct 29, 2018
Messages
21,709
Actually, I've been tinkering further and this (inconsistent output to memory and the Immediate window) seems exactly to be what is occurring.

I tested a variety of means to obtain or assign the string output, without success. Given the input I described, the VBE, as compiler / command interpreter / shell consistently outputs Null to memory and the string "Null" to the Immediate window. In all other cases of Null, the VBE prints nothing to the Immediate window.

So, it turns out the syntax I described doesn't return the string "Null" after all, it just tricks the VBE into outputting it to the Immediate window. I can't imagine a reason for such inconsistent output, and many reasons to avoid it, so I presume it is unintentional even if an arcane explanation exists.
Not sure I understand the original idea, but just did a quick test with the following result.
1720044757755.png

Were you expecting nothing to show up in the result?
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
I think

I think what it prints is that the variant evaluates to Null, not that it evaluates to a string of "Null". Further testing, such as getting the Len() of the variant should confirm that.
Len() (and LenB()) are two tests I hadn't attempted. I tried them just now and both return Null, which one would expect for a Null input but not for a string.

This said, I tried a number of other things all related to evaluation or type conversion in one form or another, so you may be onto something in suggesting that the syntax triggers evaluation somehow. Evaluation is somewhat of a dark art in VBA, it seems, more often done implicitly but also triggered by delimiters.

So, parentheses can be used to evaluate an assignment statement, e.g., `x = y` as a Boolean expression, e.g., `If (x = y)`. Quotation marks force evaluation of strings. Square brackets are shorthand for the Excel Evaluate method,, apparently the hidden _Evaluate method of many Access objects, and, I believe, other procedures with DISPID = 5. Eval() seems like an implementation of a Win32 Evaluate method. Percentage signs (%) force evaluation of environment variables.

Octothorpes are expressly shorthand for DateValue() according to its documentation but the function accepts only a String argument. This tells me the function may be a wrapper for a Win32 function that does more and is what octothorpes actually call because of the behavior when octothorpes delimit a Null Variant variable. For dates, DateValue() is essentially the inverse of Format(), which does both type conversion and formatting. DateValue() probably does its own conversion and formatting, printing according to the localization settings while returning a Double. Its parent function, when called with octothorpe delimiters, may in the same fashion print the string "Null" while returning Null itself.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Today, 04:18
Joined
Feb 28, 2001
Messages
27,697
I looked in the MS VBA Language Spec (version dated 24 Apr 2014) and unfortunately it doesn't specify a mechanism for constant evaluation - which is what would happen for # Null # as an input sequence. It merely states how the implied/explicit number would be interpreted. There is no mention of an implied function call. I suppose constant evaluation could be treated as an overloaded function call implicitly.
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
Why does it all matter anyway?
What are you doing with this construct?
Very good questions, actually.

I was just framing out two or three generic upstream helper functions to do some small things (mostly relating to delimitation) to facilitate dynamic construction of SQL statements and criteria expressions when the behavior manifested.

I've exploited other undocumented behavior I have observed to great effect and so am keen to find other instances. This one seems increasingly like a coding error in the compiler, or a quirk of the DateValue() parent function that octothorpes (as a shortcut) call, so is probably worthless, but others have been far more deliberate and well-implemented and thus exploitable. The VBA devs dropped breadcrumbs all over and I've just learned to be alert to them.
 

riktek

Member
Local time
Today, 02:18
Joined
Dec 15, 2023
Messages
51
I looked in the MS VBA Language Spec (version dated 24 Apr 2014) and unfortunately it doesn't specify a mechanism for constant evaluation - which is what would happen for # Null # as an input sequence. It merely states how the implied/explicit number would be interpreted. There is no mention of an implied function call. I suppose constant evaluation could be treated as an overloaded function call implicitly.
I'm not certain that Null is a constant but leaving that aside, I think George was on to something by suggesting this behavior is the consequence of an evaluation. Delimiters trigger evaluation in VBA and Windows, and in Bash, for that matter. Octothorpes trigger evaluation of date literals in strings., i.e., DateValue() (according to its documentation0. The [MS-VBAL] can be profoundly revealing but ultimately it's implemented with MFC or other Win32 classes. DateValue() won't take a Null argument but the function its shortcuts (i.e., octothorpes) call, will. This tells me that the behavior probably is a consequence of how DateValue() implements the parent W32 function that octothorpes call.
 

gemma-the-husky

Super Moderator
Staff member
Local time
Today, 10:18
Joined
Sep 12, 2006
Messages
15,811
Perhaps this is new, or just new to me, but I just learned that a string that concatenates a Null Variant variable between octothorpes using Null propagation (by use of the + operator) does not return Null but rather the string "Null" (without the quotation marks).

This can be handy but I just can't figure out why that would be. An hour with Google was fruitless.

Here's the function:

Code:
Function TestNullVariant() As Variant
    Dim varReturn As Variant
    Dim varTest As Variant
   
    varTest = Null
    varReturn = "#" + varTest + "#"
   
    TestNullVariant = varReturn
End Function
Out of interest what would happen if you used a different variable type, other than a variant, as variant is very much a special case.

Normally that expression would return a date with a valid string in vartest. Would it return a string if everything was of type string?
 

Users who are viewing this thread

Top Bottom