Search code examples
stringdimplicit-conversionboolean-logic

Shouldn't Empty Strings Implicitly Convert to false


Why does

if (x) {
    f();
}

call f() if x is an empty string ""?

Shouldn't empty strings in D implicitly convert to bool false like they do in Python and when empty arrays does it (in D)?

Update: I fixed the question. I had incorrectly reversed the reasoning logic. Luckily, the bright D minds understood what I meant anyway ;)


Solution

  • Conditions and if statements and loops are cast to bool by the compiler. So,

    if(x) {...}
    

    becomes

    if(cast(bool)x) {...}
    

    and in the case of arrays, casting to bool is equivalent to testing whether its ptr property is not null. So, it becomes

    if(x.ptr !is null) {...}
    

    In the case of arrays, this is actually a really bad test, because null arrays are considered to be the same as empty arrays. So, in most cases, you don't care whether an array is null or not. An array is essentially a struct that looks like

    struct Array(T)
    {
        T* ptr;
        size_t length;
    }
    

    The == operator will check whether all of the elements referred to by ptr are equal, but if length is 0 for both arrays, it doesn't care what the value of ptr is. That means that "" and null are equal (as are [] and null). However, the is operator explicitly checks the ptr properties for equality, so "" and null won't be the same according to the is operator, and whether a particular array which is empty has a null ptr depends on how its value was set. So, the fact that an array is empty really says nothing about whether it's null or not. You have to check with the is operator to know for sure.

    The result of all this is that it's generally bad practice to put an array (or string) directly in a condition like you're doing with

    if(x) {...}
    

    Rather, you should be clear about what you're checking. Do you care whether it's empty? In that case, you should check either

    if(x.empty) {...}
    

    or

    if(x.length == 0} {...}
    

    Or do you really care that it's null? In that case, use the is operator:

    if(x is null) {...}
    

    The behavior of arrays in conditions is consistent with the rest of the language (e.g. pointer and reference types are checked to see whether they're null or not), but unfortunately, in practice, such behavior for arrays is quite bug-prone. So, I'd advise that you just don't ever put an array by itself in the condition of an if statement or loop.