The solution to "Error handling"...

Dennis dkorpel at gmail.com
Mon Jul 6 12:00:29 UTC 2026


On Sunday, 5 July 2026 at 21:57:55 UTC, Meta wrote:
> Rather than have his program crash when it tries to dereference 
> a null pointer, he wants to paper over it and keep going like 
> nothing's wrong. A segfault or an assert triggering is the 
> correct behaviour in this case;

I have to admit that I find his example of a nil-struct a bit 
abstract. But to me, the takeaway is not "replace null checks 
with nil structs and pretend everything is fine now". The idea is 
that you rethink your design so the whole concept of `null` 
wasn't there in the first place.

In math, the product of an empty set is defined as 1. This is a 
bit jarring at first, but in practice it works out beautifully in 
formulas and prevents discrete cases. A programmer might be 
tempted to implement `throw new Exception("at least 1 number 
expected as input for product()")` and impose unnecessary 
branches for 'error handling', when there was never a need for an 
'error' to begin with.

In Java, an ArrayList can be null, forcing null checks like:

```Java
if (xyzList != null && xyzList.size() > 0) doSomething();
```

https://stackoverflow.com/questions/29784314/can-an-arraylist-be-null-and-have-a-size-0

In D, you can always check `array.length`. It's designed so that 
whenever `array.ptr` is null, `array.length` is also 0 (save for 
`@system` shenanigans), defining the null error out of existence 
even when the variable is 0-initialized. I love that design!

> What if he wrote a text editing program that uses this 
> philosophy? When the user wants to save their work, and fopen 
> returns such a "nil struct" instead of a null pointer, it would 
> appear to the user that their file was saved to disk, only for 
> it to be completely lost once the program exits.

Defining errors out of existence is a hard sell, because it's not 
a single pattern that you universally apply. It's a case-by-case 
thing that requires real context and critical evaluation of your 
entire stack. This is indeed a case where plainly applying the 
'nil struct' pattern is a bad idea. Instead, you could question 
why your application is 'opening a file' in the first place and 
why it would have the responsibility to error check.

What if perhaps, your application would hand off the 'save data' 
to the OS/browser/ui framework/whatever, and make it their 
responsibility to write it to disk and report errors back to the 
user? Notice how in this shell command, it's zsh reporting the 
error:

```
echo "hello" > dummy/dummy.txt
zsh: no such file or directory: dummy/dummy.txt
```

echo simply writes to stdout without doing fopen itself, so it 
doesn't have to do this error check. I know this doesn't define 
the error literally out of existence, it just makes it someone 
else's problem. But you can imagine if you have 100 shell 
programs like this, that's now 99 less error checks.

As an aside, notice how when you 
`fopen("chain/of/directories/file.txt")`, you get to check 1 
error. But behind the string API, conceptually you are doing 
`get("chain").get("of").get("directories").get("file.txt")`.
Each of these can fail, so you could also handle 4 different 
error branches.
Now compare this snippet from the article:

```C
Node *n1 = ChildFromValue(root, 1);
Node *n2 = ChildFromValue(n1, 2);
Node *n3 = ChildFromValue(n2, 3);
Node *n4 = ChildFromValue(n3, 4);
```

Do you see the resemblance? 🙂

> Also, who unironically thinks errno is a good way to handle 
> errors in 2023?

He said "there are reasonable aspects of its design". It being a 
global variable and only a single integer of information is 
certainly crappy. But I personally do agree with the principle 
that actions should prefer producing result data AND error data 
instead of result data OR error data. I personally implement this 
by returning the result, and putting error data in an `ErrorSink` 
parameter.


More information about the Digitalmars-d mailing list