This syntax regarding null checking baffles me

kdevel kdevel at vogtner.de
Sun Jan 10 14:40:04 UTC 2021


On Sunday, 10 January 2021 at 10:42:48 UTC, Jonathan M Davis 
wrote:

[...]

> IIRC, if the class overrides opCast for bool, then
>
>     if(c)
>
> will cast the object to bool and use the result for the if 
> condition,

Well, no:

```null.d
import std.stdio: writeln;
class C {
    bool opCast ()
    {
       return true;
    }
}

void bar (C c)
{
    if (c) writeln (3);
    else writeln (2);
}

void foo (ref C c)
{
    if (c) writeln (5);
    else writeln (4);
}

void main ()
{
    C c; // null ref
    if (c) writeln (1);
    else writeln (0);
    bar (c);
    foo (c);
    auto x = cast (bool) c; // crash as expected
}
```

$ ./null
0
2
4
Segmentation fault

BTW: Correctly using variables of class or in case below of AA 
type
takes some getting used to. A few day ago I ran into a bug with a 
helper
function "merge" in a context like this:

```ini.d
import std.stdio;
void merge(T) (T a, T b)
{
    foreach (k, v; b) {
       if (k in a)
          throw new Exception ("key <" ~ k ~ "> already set");
       a[k] = v;
    }
}

void main ()
{
    string[string] data;
    data = ["a": "A"]; // <---- comment me out! (*)
    auto other_data = ["x": "X"];
    data.merge (other_data);
    writeln (data);
}
```

As expected one gets:

    $ dmd ini.d && ./ini
    ["a":"A", "x":"X"]

Now it happened that in the course of development there was a code
path in which data was not initialized (*). Guess what the output 
was!

    $ dmd ini.d && ./ini
    []

A void merge(T) (ref T a, T b) is required to cover the 
uninitialzed
case. That was a rather surprising experience.


More information about the Digitalmars-d mailing list