Preferences

I don't believe it is possible (or even makes sense) to completely avoid illegal/invalid objects and structures, and a cheap way to mark these are nil pointers. From that perspective, it doesn't matter to me whether a language allows nil pointers or doesn't have them. What matters are the details, though. It is generally desirable to keep invalid objects properly typed and languages with nil sometimes have quirks with "nil typing" (I'm not sure if that's the right term).

WUFFS is an example of a language which just doesn't have any of these "illegal/invalid objects".

Safe Rust doesn't have any either, though presumably you'll say "but unsafe" there.

> It is generally desirable to keep invalid objects properly typed

As written this doesn't mean anything, if the object is properly typed then it is valid, an invalid object can't be properly typed. So more likely you're imagining something like Rust's MaybeUninit<T> type wrapper which says well, either this is a T, or it isn't (yet) and so a programmer will need to tell the compiler once they've arranged that it is a T so then it can be used as a T.

Barry Revzin has (I think) landed the fixes to the C++ type system so that you could reasonably write this in C++ too once you have C++ 26.

It is impossible not to have invalid objects in a real-world system with i/o and dynamic memory allocation. Perhaps there is some semantic confusion between us, however. What you consider an invalid object doesn't exist in my parlance. I'm not even sure I understand what you mean by it. What I mean by an invalid object is an object or structure of a certain type that is in an unexpected state, a state does not allow further regular computation with it. It's some sort of error state.

For example: Dynamic memory allocation can fail. Input might fail. Input validation might fail. Hence, any object with dynamically allocated memory and any object processing input might become invalid in that sense.

You have to deal with such cases in any programming language and the source of error is the same in any of them. Nil is not an "additional source of error" or anything like that. Inadequate typing of nil (instead of having option types) might create an additional source of error but that depends on the language and it doesn't need to.

On a side note, those type system fixes may be neat for people who like typed logics but they are mostly pointless because the invalid state occurs at runtime.

What's happened is that you've been poisoned so badly by languages like C that you no longer even understand what's actually going on.

Your world becomes a bewildering mess in which it seems as though nothing can ever be trusted, and so you stumble into either writing endless checks because you're never sure of anything, or you throw your hands in the air and pronounce doing nothing "good enough" then blame others when inevitably your software doesn't work.

Take Rust's Allocator::allocate, defined as:

    fn allocate(&self, layout: Layout) -> Result<NonNull<[u8]>, AllocError>;
Yes, our allocation might fail, and in this case our result is Err(AllocError). That's a perfectly good result, and a perfectly good allocation error. It's not the memory you wanted, because your allocation failed, but it's not "invalid" in any useful sense.
WTF? I don't even program in C - but I do know Rust (and Ada). Being a little bit less condescending would go a long way if you want to be taken seriously. So much for the tone.

To address the content: Yes, you have to deal with that error result just like you have to deal with a nil pointer. No difference. That's the point.

By the way, the toxic behavior of the Rust community is one of the reasons why I barely use the language.

What would change your mind regarding ruling out illegal structures?

In an alternative universe, there could be n sentinel non-values, instead of a single null.

There could be "null" ("I am initialising this memory as uninitialised"), but there could also be "egad" ("this pointer refers to memory on a different page"), there could be "biff" ("this address is on another caller's stack").

There are infinite ways you could design a language which lets you take invalid memory and tell the type system it's a Sheep, when it's not. Some of those languages might even have sophisticated biff-checkers or raise EgadReferenceExceptions.

What's stopping you from throwing out null along with biff and egad?

> I don't believe it is possible (or even makes sense) to completely avoid illegal/invalid objects and structures, and a cheap way to mark these are nil pointers

Obviously we should be able to represent objects with possibly invalid state, but rather than allowing a "possibly invalid value" as a legitimate member of a huge number of types, which is what nil/null permits, the possible invalidity should be it's own type, like a MaybeInvalid<T>. Even languages that bake null checking into the type system are doing this, and then just inserting implicit conversions to/from such a type.

>It is generally desirable to keep invalid objects properly typed

I think that's the bigger issue in Java. `int` can't be used in generics, so now you use the boxed type `Integer` which needs to be checked on each use, which depending on the usage is a lot of work.

If Java had proper generics without this workaround, we wouldn't have nearly as many issues.

This item has no comments currently.

Keyboard Shortcuts

Story Lists

j
Next story
k
Previous story
Shift+j
Last story
Shift+k
First story
o Enter
Go to story URL
c
Go to comments
u
Go to author

Navigation

Shift+t
Go to top stories
Shift+n
Go to new stories
Shift+b
Go to best stories
Shift+a
Go to Ask HN
Shift+s
Go to Show HN

Miscellaneous

?
Show this modal