Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

NULL isn't the uninhabited type, that's the bottom type. NULL is a value that inhabits every type.



Not in all languages. In Lisp dialects related to classical Lisp, like ANSI Lisp, there is a unique nil object which is a kind of symbol. It is self-evaluating and serves as (the one and only) Boolean false value, and also as a representation for the empty list, which terminates all non-circular lists.

There is no nil-like value in the domain of any other type. If you hold a value which satisfies stringp then you know you have a string of zero or more characters and not some null reference.

Because the typing is dynamic, then if you have a situation in which you would like to either have a string, or a value indicating "there is no string here now", you can use nil for that. But replacing a string variable with nil changes the type; it is not a string reference that has been nulled out, but a string object previously stored in the variable has been replaced with the nil object.


I think he's speaking specifically of the Algol-derived languages that the article is talking about, i.e. C, C++, Java, etc. Other languages (eg. SML, Ocaml, Haskell, and Rust) force you to make None an explicit value in an algebraic type (eg. Maybe/Optional), and that's what the article is arguing for. In dynamically-typed languages (Python, Javascript, Ruby) the question is irrelevant because there's no static type checking anyways. Static type systems bolted on top of dynamic languages (eg. CMUCL, Closure Compiler, TypeScript, Python typing) often get this right - they treat a nullable type as distinct from a non-nullable one and perform checking upon entry. There're also some languages (Kotlin, Java8 with @NonNull) that are fundamentally saddled with null because it's part of the platform APIs, but have built layers on top of it similar to these to perform nullability checks.


> NULL is a value that inhabits every type.

Not in all type systems. Particularly, type systems which has union types may chose to simply create a separate type for NULL. There are also variants that have separate NULL types for different base types, which also invalidate your claim.


> Not in all type systems

I think this is inaccurate. We are talking about computer science, which is important and a constraint around the general type theory. A type system is different than how you interact with it, so dispensing with language-specific symbolic representation further normalizes the discussion.

Fundamentally, a (computer science) type is a representation of binary, for the most part, data. That representation has to inhabit some part of bounded memory. When that memory is initialized (empty), it's some form of NULL, for a lack of another term. It exists for every type system in computer science.

> There are also variants that have separate NULL types for different base types, which also invalidate your claim

That's not the same thing. Different NULL types make sense for different sized discrete (fixed bounds) memory allocation. A unicode character has a fixed size allocation, while a string might be unbounded allocation (it grows in some fashion, as needed).

Edit: Kneejerk downvoting, classy.


This does not make sense. Null is not the same as zero and neither is the same as an all-zeros bit pattern. A memory word interpreted as an integer has no meaningful null value. A memory word interpreted as a pointer may or may not have a special bit pattern (which may or may not be the same as integer zero) that represents a pointer to nowhere; it all depends on language semantics. The address 0x0 can be perfectly valid on some architectures. Even though in C the literal 0 denotes a null pointer constant, it does not mean that the value of a null pointer is literally zero.


> A memory word interpreted as an integer has no meaningful null value.

What a type is, depends on what the runtime operates on. You can make a runtime that just grabs random bits of data as a type and say "that's an integer" but it's not a useful construct/example. A runtime keeps track of types in some way external to the data itself. So I'll disagree that an all-zeros is not the same as a null, because it's a common way to initialize the data that is identified with a type (like in a pointer table). It's not a 1:1 but it's common. There's not always a formalized name, but it (an uninitialized state) always exists as part of the type system (when not reusing existing memory allocation, which is an initialized state). Always.


It was not I that downvoted you, but I agree with the down-voter in that you are not making good arguments. There is basically nothing in common with NULL as used by programming languages in general compared to how you want to define it in your comment. How NULL is represented internally, is totally language dependent. C and its ilk has defined it one way (that is reasonably close to your description ON SOME ARCHITECTURES - not all), but how other languages define it differ wildly.

And strings may only grow if strings are mutable, which AGAIN is extremely language dependent.


I’m not sure I buy this definition of type even in theory.

From a category theoretic point of view a type would be nothing more then the constraints on how terms may be composed.

Either you simply view types as as objects in some category or, perhaps a bit more interesting, as a functor. See f.ex http://noamz.org/papers/funts.pdf

Or rather it seems to be a common theme in language design to conflate these two notions of types, and we should probably stop doing that.


Category theory doesn't require NULL but physical state does. Given the state of the machine as a constraint, there must be an uninitialized state of unknown or undefined (but allocated) for each type to ensure types are run as functors. I don't see why talking about the theory is useful, given the practical constraint will always provide an asterisk of *given you're working on physical memory

All types are functors in practice...which always has an element of initialization to ensure the type is defined in the memory.


But that is a big asterisk, which was my point. Only the compiled and running program is actually forced to working with physical memory. All stages before that is just modeling.

My belief is that we should stop conflating data types (input and state modeling) and program types (domain modeling) so we can advance to more productive workflows. F.ex runtime reflection should never have been a thing, instead the focus should have been on macros and staged compilation, most meta programming can probably be better evaluated design time rather than run time.


Well said.


Sorry, I was talking specifically about C++ and friends, which is the set of languages for which NULL is considered problematic. For the languages you're talking about, NULL is much more well-behaved, so there's less reason to complain.


Thank you. I got confused on nomenclature because of a null pointer's similarity to the bottom type.

I was trying to say that having a NULL value that inhabits every type seems silly as not every set of values has the NULL value. Considering that NULL can be represented as a special case of sum types, it seems even sillier to mandate such a value on all types.

Using both NULL and nullable seems very confusing as well.


Consider Javascript, where undefined and null are both unique primitive values.


Is anyone aware of a situation that code would fault if we replaced all undefineds with nulls in JS?

General code, not things specifically testing differentiation between undefined and null.




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: