Live data from Hacker News

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

lucidchart.com

321–330 of 377 posts

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

#321
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…

Not very difficult. Just provide a not_null pointer attribute, just like const. Then require that all dereferenced pointers must have the not_null attribute. Problem solved.

(Other note: C++ has a not_null pointer-like type: it's references. Unfortunately, C++ references cannot be reseated, which makes wholesale replacement of pointers not feasible. Plus, the language doesn't actually forces you to check pointers before assigning to a reference.)

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

#322
post #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.

There's a fundamental difference between the Rust approach of the library providing a function for opting-in to potential crashes and the C/Java approach of not distinguishing that case at all. The programmer still is forced to write a null check, it's just a check that crashes the program.

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

#323

Earlier quoted context omitted.

All of those different nulls can be solved by not having null as a special case of your database specification, but as a first class type construct. data MightBeData a = Yes a | Unavailable | NotApplicable | NeverApplicable

NULL in databases have many properties that save a shitload of coding time and help write more secure code. To cite only one of theses useful properties NULL automatically propagate through all operations and aggregations.

Is that the behavior you actually want, though? In many cases "this value is explicitly unknown" has dramatically different semantics from "the computation that produced this value had an unexpected NULL input", and if you interpret the latter as the former, you've likely just corrupted your data.

Monadic Maybe (in higher-level languages like Haskell or Rust) has the semantics you describe, but the advantage that you only get it when you explicitly ask for it. If you care about data integrity you usually want to be particularly precise about the results of your computation; it's helpful if your type system can sanity check them as they propagate through every operation.

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

#324

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”.

I have worked with a MySQL database where the designer(s) decided that, on many of the tables, -1 should represent no value instead of null. As you can imagine, this has caused some problems when they've done this with columns representing dollar amounts. This was done because of their belief that having any nulls in the table is the kiss of death for performance; they've used the phrase "tablescan" a lot. I have not…

Databases, and MySQL in particular because of how many of it's defaults are pants-on-head nonsensical, are a haven of cargo cult performance rituals. I have a suspicion this is because, rather than analysing their own N! loops/queries, it's easier for mediocre programmers just to blame the database.

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

#325

Earlier quoted context omitted.

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 kn…

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.

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

#326
post #246
post #223

Earlier quoted context omitted.

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)…

These are great features, but they are really just syntactic sugar over algebraic types. It's not a more pleasant developer experience than sum (Option) types, it's a more pleasant experience with sum types. Ex: macro! unwrap(x, fallback) { match x { Some(n) => n, None => fallback }; } > 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…

It's subtly different because of the implicit coercions and smart casts. You can always pass T to a function that takes T?, while in Haskell/Rust you would need to pass Some(t). Similarly, Kotlin does control-flow analysis and converts all T?s inside an "if (t != null) ..." block or after an "if (t == null) return" statement into a T, which dramatically reduces the amount of try!/unwrap() calls that I used to see littering early Rust code. There's better syntactic sugar for it in Rust now, but the point is that Kotlin doesn't need nearly as much syntactic sugar because nullable is integrated with the typechecker and flow analysis.

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

#327
post #207

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…

My degree's in mathematics and I share your disdain for pointer bit-twiddling. I still find SQL nulls difficult to reason about or diagnose. I'm sure there are times and places when their behaviour is what you want but most of the time they're just a big extra complication that you don't want or need.

In the tables I define everything is not null with sane defaults by default.

The places I do allow null are few and far between (e.g. updated_at) and I'm struggling to think of instances I've used them as anything other than absence indicators.

In fact I don't think I ever treat it as anything other than that in code either.

Was the purpose of null ever to mean anything other than I have not been defined/set?

All my objects are statically typed so I never run into the issue of testing is thing.x a thing, it's always a thing, or it's a compile error. It's either set or not set, and thanks to the database convention I only have to worry about certain values having null, most of the time it makes sense anyway. Is updated_at turthy doubles as has been updated tests.

Am I incorrect in this method? With this method I fail to see big extra complication. Will switching to option types help me? I debate they will not. But I'm happy to be convinced. I do avoid nulls. I just haven't seen a problem with them in my own code. (Not true for others)

Specifically, with the caching problem, provided you constrain the cache to reason about null == not set. I see no problem.

    Cache.get(K) // null
    Cache.set(K,3) // void
    Cache.get(K) // 3
    Cache.set(K, null) // deletes, void
    Cache.get(K) // null
    Cache.set(K, false)
    Cache.get(K) // false
Only certain values of mine are going to potentially be null from the database, all of which will be contained within serialised objects.

I just never see the issue the author has. The times K do see it are when people get too clever with default values.

I understand it, I just don't see it in practice. Certainly my not frequently enough to make language changes.

Title should just read "Stop abusing null" because the only time I've seen it be an issue is when people are dual encoding meaning.

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

#328
post #198

You know who works on a platform with NULL but doesn't have quite so many problems with it? DBAs. There's some need to draw a distinction between the basic idea of NULL, and the way that NULL has been implemented in most high-level programming languages. In most RDBMSes, values can't be null unless you say they are. Sometimes explicitly, as in table definitions, sometimes implicitly, when you select a JOIN type. Eith…

NULL in SQL really isn't great. For one, nullable table columns is a bad default, and you have to explicitly write out "NOT NULL" to avoid this behavior. I'd say that 90% of the time I want not-null table columns, and only 10% of the time do I want a nullable column. Secondly, NULL has weird arithmetic. It turns out that NULL=NULL is false, and NULL NULL is also false. (This is unlike C/Java/Python/etc. by the way.)…

> NULL in SQL really isn't great. For one, nullable table columns is a bad default, and you have to explicitly write out "NOT NULL" to avoid this behavior.

This is not true on many dbms. It's an implementation choice.

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

#329
post #315

Earlier quoted context omitted.

Accesses to unallocated global data is the type of errors that you typically hit on the first test run. Another example would be function pointers loaded from DLLs. I don't think type systems help all that much. Type + instead of -, and you're out of luck.

> Accesses to unallocated global data is the type of errors that you typically hit on the first test run. Depends what conditions cause it; the hard part is being sure that every possible code path through the first stage will initialise the data, even the rare ones like cases where some things time out but not others. > I don't think type systems help all that much. Type + instead of -, and you're out of luck. Not m…

1) Pretty easy to guarantee if main looks like stage1(); stage2(); stage3(); etc.

2) Change a plus for a minus and it is still an int.

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

#330
post #188

in C NULL is just 0. a nullptr in c++ is just a pointer which points to 0. so it's not an undefined value... it's set to 0 on purpose so you can check it. consider this: char ptr; ptr = (char )0xb8000; before assigning ptr, ptr can be ANY value from 'random memory'. (compiler trickery aside.. because it might initialise it to 0 anyway...) so you want to have: char ptr = NULL; ptr = (char )0xb8000; So you can then do…

Proper typesafe systems wouldn't let you use C-style reinterpretation casts either. It's quite instructive to see how the low-level Rust people handle this.

So if you have memory-mapped IO, how would you write to a specific address? In C/C++, a reinterpret cast is exactly what you need there. What would you use in Rust?
Post reply on HN