Checking if a string is null

Frits van Bommel fvbommel at REMwOVExCAPSs.nl
Wed Jul 25 06:05:25 PDT 2007


Regan Heath wrote:
> Max Samukha wrote:
>> Using '== null' and 'is null' with strings gives odd results (DMD
>> 1.019):
>>
>> void main()
>> {
>>     char[] s;
>>
>>     if (s is null) writefln("s is null");
>>     if (s == null) writefln("s == null");       
>> }
>>
>> Output:
>> s is null
>> s == null
>>
>> ----
>>
>> void main()
>> {
>>     char[] s = "";
>>
>>     if (s is null) writefln("s is null");
>>     if (s == null) writefln("s == null");       
>> }
>>
>> Output:
>> s == null
>>
>> ----
>>
>> Can anybody explain why s == null is true in the second example?
> 
> Not I, it's inconsistent IMO and it gets worse:
> 
> import std.stdio;
> 
> void main()
> {
>     foo(null);
>     foo("");   
> }
> 
> void foo(string s)
> {
>     writefln(s.ptr, ", ", s.length);
>     if (s is null) writefln("s is null");
>     if (s == null) writefln("s == null");
>     if (s < null)  writefln("s <  null");
>     if (s > null)  writefln("s <  null");
>     if (s <= null) writefln("s <= null");
>     if (s >= null) writefln("s <  null");
>     writefln("");
> }
> 
> Output:
> 0000, 0
> s is null
> s == null
> s <= null
> s <  null
> 
> 415080, 0
> s == null
> s <= null
> s <  null
> 
> So, "" is < and == null!?
> and <=,== but not >=!?

As Max said, you forgot to update some writeflns. The output of the 
corrected version is:
===
0000, 0
s is null
s == null
s <= null
s >= null

805BEF0, 0
s == null
s <= null
s >= null
===

Seems perfectly consistent to me. Anything with an equality comparison 
(==, <=, >=) is true in both cases, and 'is' is only true when the 
pointer as well as the length is equal.

> This all boils down to the empty vs null string debate where some people 
> want to be able to distinguish between them and some see no point.
> 
> I'm in the 'distinguishable' camp.  I can see the merit.  At the very 
> least it should be consistent!

They *are* distinguishable. That's why above code returns different 
results for the 'is' comparison...

I for one am perfectly fine with "cast(char[]) null" meaning ".length == 
0 && .ptr == null" and with comparisons of arrays using == and friends 
only inspecting the contents (not location) of the data.

Now, about comparisons: array comparisons basically operate like this:
---
int opEquals(T)(T[] u, T[] v) {              // bah to int return type
     if (u.length != v.length) return false;
     for (size_t i = 0; i < u.length; i++) {
         if (u[i] != v[i]) return false;
     }
     return true;
}

int opCmp(T)(T[] u, T[] v) {
     size_t len = min(u.length, v.length)
     for (size_t i = 0; i < len; i++) {
         if (auto diff = u[i].opCmp(v[i])) {
             return diff;
         }
     }
     return cast(int)u.length - cast(int)v.length;
}
---
(Taken from object.TypeInfo_Array and converted to templates instead of 
void*s + casting + element TypeInfo.{equals/compare} for readability)

Since both the null string and "" have .length == 0, that means they 
compare equal using those methods (having no contents to compare and 
equal length)

This is all perfectly consistent (and even useful) to me...


More information about the Digitalmars-d-learn mailing list