Live data from Hacker News

NULL: The worst mistake of computer science? (2015)

lucidchart.com

221–230 of 377 posts

Re: NULL: The worst mistake of computer science? (2015)

#221
post #168

Earlier quoted context omitted.

NULL in SQL is a notorious source of errors and confusion (particularly when it comes to e.g. tri-state boolean logic). It certainly can come from nowhere and surprise you - if anything the behaviour is even worse than in Java or C#. So I don't think there's anything to learn from there. (Rather what modern languages should have done - and increasingly do - is follow ML practice and avoid null entirely, implementing…

That's not really NULL's fault that it causes confusion in SQL. That's just ternary logic. People who don't handle NULLs in SQL aren't really mishandling the NULL. NULL is just a value. They're simply failing to understand the Boolean value of UNKNOWN and what that means. They're so used to thinking only in bivalent logic that the additional complexity throws them off. However, "It's more complex for me to think abou…

> Or arguments about zero-based array indexing. These concepts aren't difficult. They're just more complex. Negative numbers aren't difficult, but they're more complicated than just cardinal numbers. Fractions and decimals aren't difficult, but they're more complex than integers. Multiplication and division aren't difficult, but they're more complex than addition and subtraction.

We usually consider it a good thing when programming languages let you opt out of the complex thing. In a good language, you can do integer arithmetic if you don't want to deal with fractions or decimals. You can do cardinal arithmetic if you don't want to deal with negative numbers. You can do ordinary Boolean logic if you don't want to do ternary logic.

The problem with SQL isn't that it has NULL. It's that it's too hard to not have NULL. Which is the problem with null in general.

Re: NULL: The worst mistake of computer science? (2015)

#222
post #202

Earlier quoted context omitted.

I guess. My tendency is to think that it's more a problem for developers who are new to SQL, and are surprised to find out that, despite having the same name, nulls in SQL don't have the same semantics as nulls in other languages. Once you get a handle on the semantics, though, they make a lot of sense. The trick is to understand how SQL's NULL is rooted in mathematical formalism, not the pragmatics of dealing with p…

In SQL, NULL NULL yields false. You use IS NULL / IS NOT NULL to test for NULL values. In programming languages, NaN!=NaN yields true. You use x!=x to test for NaN values. Saying that SQL NULL is rooted in mathematical formalism doesn't explain anything, because anything (even nullptr and NaN) can be explained in mathematical formalism. What we want is a simple semantic model that a human can understand and one that…

I thought in most (many?) languages NaN != NaN ?

Re: NULL: The worst mistake of computer science? (2015)

#223
post #205

Earlier quoted context omitted.

It needs to be supported at the type level, whether by null or by options, simply because “data not available” is a common value people need to use. When there’s no good way to express it, they’re forced to invent special sentinel values, and you end up in the situation where array index -1 means “value not found in the array”.

Yes, option types are awesome. No, they are not nulls. Algebraic data types are not direct support "no data found at the type level". Algebraic types are really just a fancier enum/union type. It just so happens that inventing special sentinel values is awesome when you have an algebraic type system to check your work.

Take a look at Kotlin or Typescript†. Basically, they decided to fully design the language with support for null-as-option.

That means several things:

  * T (non-nullable) and T? (nullable) are different types. T? = T | null
  * Where T is expected T? is not accepted, but where T? is specified T is also accepted
  * T? is automatically cast to T in the places where it's asserted to be not null, e.g. within an if(x != null) branch
  * Method calls are not allowed on T? (unless the function specifies it can handle null)
  * There's syntax for providing a value in case of null. (x ?: fallback) in Kotlin, (x || fallback) in Typescript. 
It's a much more pleasant developer experience than the Option ADTs/Enum types from Scala or Haskell, which the same amount of safety.

Typescript goes even further and has the best enumeration support I've seen any language have. T | U is a fully valid type, and if T | U is asserted to be one of them it is automatically cast to T/U. It is a very natural and efficient way of building ADTs [1]

† Typescript 2.0+ with --strictNullCheck on

[1] https://www.typescriptlang.org/docs/handbook/advanced-types.... , Discriminated Unions header

Re: NULL: The worst mistake of computer science? (2015)

#225
post #202

Earlier quoted context omitted.

In SQL, NULL NULL yields false. You use IS NULL / IS NOT NULL to test for NULL values. In programming languages, NaN!=NaN yields true. You use x!=x to test for NaN values. Saying that SQL NULL is rooted in mathematical formalism doesn't explain anything, because anything (even nullptr and NaN) can be explained in mathematical formalism. What we want is a simple semantic model that a human can understand and one that…

> In SQL, NULL NULL yields false. It yields NULL, not false. So do NULL = NULL or NOT NULL.

NULL isn't a Boolean value in ternary logic any more than 3.2 or 'Hello' or December 12, 2018, have Boolean values. It's UNKNOWN. UNKNOWN is related to NULL, but they don't work identically.

NULL is a value that any column data type can potentially have. NULL is what comparison and evaluation operators work with. UNKNOWN is a ternary Boolean type, and the Boolean type is what Boolean operators work with (AND, OR, NOT) and nothing else. This Boolean type in an RDBMS is unavailable to the user and is for internal evaluation purposes only. RDBMSs that support a "bool" type are not implementing the same thing. You can never say UPDATE MyTable SET Col = Value1 AND Value2. That's not going to work. Many RDBMSs have a documentation page that explains this difference, like this one[0] from Microsoft SQL Server.

Notably, NULL + 3 and NULL * 5 are both NULL. Any mathematic operation on NULL is NULL. But UNKNOWN AND FALSE is FALSE, and UNKNOWN OR TRUE is TRUE.

[0]: https://docs.microsoft.com/en-us/sql/t-sql/language-elements...

Re: NULL: The worst mistake of computer science? (2015)

#226
It is not possible to have a NULL type that works for all situations and has stable semantics.

The issue is, NULL should be a concept, not a value. I see no problem with using sentinel values, so long as they are well designed, and such good design comes with skill and experience, just as with all other aspects of architecture. The quest to have a single value that can be used for all the various possible meanings of NULL, to me, is the root of the problem.

Re: NULL: The worst mistake of computer science? (2015)

#227

Yet `Maybe | Option | ...` is not an option (pun intended), as Rich Hickey explains here: https://www.youtube.com/watch?v=YR5WdGrpoug . In effect, his argument is: 1) You have `public X Do(Y y)` changed into `public X Do(Option y)`. This will break your API. 2) You have `public X Do(Y y)` changed into `Option Do(Y y)`. This will break your API. Thus, do not use Option or equivalent in your API's. Only use a language-…

This is a spot where I've got to respectfully disagree with Mr. Hickey. Changing a public API call that used to guarantee that it returned a value so that it might now return nothing is a breaking change, and, as an API consumer, I want my APIs to broadcast that change loudly. Compiler errors are a good (but not the only) way to do that. Changing a public API member so that its arguments are now `Maybe[T]` is just si…

This is backwards. Rich did not advocate for changes that break promises.

The point in the talk is that "strengthening a promise" should not be a breaking change. Changing return type from "T or NULL" to always returning T. The case where you previously couldn't guarantee a result, but now you can.

The other case "relaxing a requirement" also should not be a problem. The case where you previously had to give me a value, but now I don't need it and can do my calculation without it.

Re: NULL: The worst mistake of computer science? (2015)

#228
post #196

NULL can mean and be different things in different domains of computer science. NULL in the database world isn't the same thing in the programming world. In the programming world, null is a result of the system architecture, systems programming, etc. In SQL, NULL is a result "lack of data". There have been debates on whether there should be different types of NULL. A NULL type for "data that is available but we don't…

This is hard to reconcile with type theory for me. NULL, to me, implies and uninhabited type, i.e. there can never be a value with a NULL type. Using null for a "data isn't there, apply, available, etc" seems like an abuse of the type system. I see no reason that the former needs to be supported at the type level. These properties are just responses to queries, not some mystical, uninhabitable oblivion. Unnecessary t…

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

Re: NULL: The worst mistake of computer science? (2015)

#229
post #195
post #41

Earlier quoted context omitted.

I would recommend looking Haskell's Maybe and Rust's Option type to get a better idea of how this can be solved -- and how this article isn't really overrated (just commonly misunderstood). They allow for explicit NULL-ness (which is a necessary concept) without falling into the trap of making everything implicitly possibly NULL. And when NULL-ness is explicit you are then forced to explicitly handle it in order for…

I dunno why everyone's assuming I don't know about the common solutions to the problem. TypeScript does explicit nullness without needing monads, and I actually mentioned that one. I still disagree that this is not overrated. Go's idea of nil, for example, seems OK to me, and the language would need to be way more complex to fix it. For example, it would need a type system with explicit nullness, or maybe even actual…

Don't get me wrong, Go does nil a lot better than some other languages (being able to call methods on a nil is sometimes a good thing depending on how your methods handle it -- most methods don't handle it well at all). The fact that even most map operations (access and deletion) also "just work" is really useful.

But I think you're over-selling the zero values feature of Go. It is very rare to see third-party libraries that have zero values which do anything but cause a NPE when you try to use them -- mainly because they embed pointers and then you have the same implicit NULL-ness that causes NPEs everywhere. It is great that the core language managed to get zero values right in most cases, but it's far from being as wide-spread as you might hope.

Also (nil interface != nil pointer that fulfills interface) is a very common mistake I see in Go code, and while it's not necessarily related to the existence of a nil value it is still related to the general concept of nil in Go.

[And on the TypeScript comment -- you don't really need monads for Option or Maybe types. You just need algebraic types -- and TypeScript has those. Haskell does use Monads for Maybe, but that's because Haskell has many other type-theory things that make it necessary to support using Maybe as a monad.]

Re: NULL: The worst mistake of computer science? (2015)

#230
post #50

> NULL is a value that is not a value. And that’s a problem. The problem isn't NULL, it's languages not enforcing the necessary checks for the "no data" condition. Option can still be NULL ("None" in rust), wrapping NULL in a struct doesn't provide any safety. The safety of Option wrapper types is from the other language features (like rust's "match") and a stricter compiler that forces the programmer to write the NU…

Even Rust doesn't have the strictness in your comment. It's perfectly fine by the compiler to make use of `x.unwrap()`: if x is None (or Err, in the case of Result), you'll just get a panic at runtime. The features you note are superior to C's offering, but purely optional.
Post reply on HN