Comment by dietr1ch
16 days ago
I think it was NULL itself. It was a long way until we realised we don't want invalid values and could use the type system to help us use special values safely.
16 days ago
I think it was NULL itself. It was a long way until we realised we don't want invalid values and could use the type system to help us use special values safely.
The problem here is that null kinda is consequential of intentional design of the type system itself. In this way, I do think that null was discovered, rather than invented. Remember, C is a kinda "portable assembler" so the constructs in it are based relatively closely to how low level data structures are mapped out in memory.
This is, and continues to be, an incredibly useful feature that makes C and C structs immensely useful concepts. Part of that does need an invalid value[1]. NULL is convenient for this and although there are some very weird JavaScript-trinity-meme-style consequences for this[2], it's such a useful concept that basically all languages that have the ability to construct pointers have a null pointer[3].
The alternative world looks like everyone inventing their own invalid values. Invalid, non-null, pointers are typically MUCH worse than null pointers for debuggability and security. If you unintentionally read/write/execute memory at 0x0 (by far the most common value for NULL), most operating systems will trap this, whereas may not necessarily if 0x12345678 is your invalid value.
[1]: Stuff like IA64 had NaT bits which were effectively an extra bit for what I assume to be this sorta thing. The problem with this is that it costs an extra bit. I don't really know much about IA64, but presumably [NaT 1] + [don't care] would be your null pointers here. I think?
[2]: Really what the standard, in my opinion, should have done is probably not make use of the null pointer UB for many different functions. A lot of compilers took the UB surrounding that to make incredibly dubious "optimizations" that broke stuff with zero actual performance benefit whatsoever
[3]: Yes, even Rust. Although some (again in my opinion) unfortunate design decisions made it so that C-Rust FFI isn't zero cost because of how it treats spans/slices
>[3]: Yes, even Rust. Although some (again in my opinion) unfortunate design decisions made it so that C-Rust FFI isn't zero cost because of how it treats spans/slices
If Rust slices already make you sad, then the thing I'm cooking up will make you cry for days.
Compared to scripting languages with actual tagged types, C doesn't really have a type system, and that's readily apparent to anyone who has written C in the last 43 years and debugged a program written in it.
C pretends types exist with you, but once bytes hit the road, it's all real-life and segmentation faults.
C actually does have a type system and it's one of the bigger issues with the language. If it didn't, unaligned pointers and signed overflow would be totally fine.
Problems with unaligned pointers are basically a hardware defect. Signed overflow is an issue because academics are unhappy computers only can do finite math.
Issue with types and C is while the compiler knows about them the standards committees don't want you to be able to. If C had first class types more people would abandon C++ and that can't be allowed to happen.
5 replies →
By that logic, no natively-compiled language has a type system.
Though I should note that in a way, even some ISAs have one, what with e.g. separate float vs integer registers.
Genuinely curious, how would you handle cases where a value is unset without NULL? This is a legitimate case that happens a lot in eg data modeling
Sum types, of course.
How do you expect to use sum types in assembly? Remember where C came from and why it was designed the way it was.
12 replies →
How are you going to build sum types in a way where you can interact with assembly or machine code? The CPU doesn't know about that stuff
9 replies →
The way we do it in modern languages with things like std::optional and even that is not the best example.
And higher level languages that works. But what do you do when you get down to low level C or assembly?
You basically end up with null/0 don’t you?
2 replies →
They already said:
> use the type system to help us use special values safely
... but this is not the place to explain what a type system is or what sum types/maybe/optional/etc. are.
Meh, I think NULL is fine in C. It's an extra, valid state to represent pointers at no cost. Unlike the more hand holdy languages, it's quite rare for a pointer in C to have the ability to be NULL since, more often than not, it's pointing at something known. It's actually quite rare to see NULL checks unless it's API code or something like that. I can see this being more of a problem in a managed language where anything can be NULL at any time.
NULL as a concept is fine. Inability to declare something as non-null is not.
There is a huge gap between developer expectation "it's pointing at something known" and hard reality confirmed by zillions of CVE. That's the reason optionality is prevalent in modern languages and type checkers (python, typescript), nowdays even Java has sane non-nullable types.
> to represent pointers at no cost
I wouldn't call "cause of bugs and security issues" "no cost".
> it's quite rare for a pointer in C to have the ability to be NULL
As a C programmer for more than 25 years, that is the exact opposite of my experience.
Struct foo has various members, including a bar*. But a foo may or may not be associated with a bar. If there's no associated bar, the bar* pointer is NULL. Seen and done this all the time
The problem with let's get rid of NULL is that it's a real, required state. The vast majority of computing is actually not binary: any real input generally has at least 3 possible states: not set, true and false.
In practice really 4 because "indeterminate" is a reasonable error condition you'd like to know about.
And it keeps increasing anyway: e.g. not set has subcategories: not set due to lack of user input, not set because we're loading state from the backend etc.
NULL is the first expression of that basic problem: it's definitely not enough to eliminate NULL because the first thing which happens is your non pointer default value takes it's place.
What you are describing is option types, which are an entirely valid and very useful construct that helps make programs more rather than less reliable. But you need proper language type system support and compile-time enforcement to make it work, and C does neither of those.
1 reply →
[flagged]
I don't know man. It's just zero. Dereferencing it just crashes your program (assuming an operating system). This kind of just reads like a fear of pointers. Corrupted/out-of-range pointers are, at least, a real problem.
Is None OK in Python?
NULL in C just doesn’t belong at the end of a string. But IMO having a “there is no value here” designation is not a bad thing.
2 replies →