14 ms·
>I’m not sure Null should have a place in programming. The essay is conflating 2 different concepts of "null." The Tony Hoare quote is about null _references
by jasode 8y ago
>I’m not sure Null should have a place in programming.
The essay is conflating 2 different concepts of "null."
The Tony Hoare quote is about null _references_ which is about aliases to computer memory. (E.g. the dreaded NPE or null pointer exception.) He's not talking about _logical_ nulls such as "tri-state booleans" or "missing data".
The logic-variant of Null usage for "unknown" "missing" "invalid" values is unavoidable in programming. This is why that null concept shows up repeatedly in different forms such as NaN in floating point, NULL in SQL language, etc. If you invented a theoretical language without logical Nulls, the users of your language would reinvent nulls using worse techniques such as homemade structs with an extra boolean "HasValue" field. E.g.:
struct NullableInteger {
int x;
bool hasvalue;
}
The "hasvalue" field becomes a "null by convention". Other programmers might not even code a verbose extra boolean variable and instead use (dangerous) sentinel values such as INT_MAX "32767" or negative value such as "-1" as the "pseudo null" to represent missing data. A lot of old COBOL programs had 99999 as some out-of-range value to represent missing data. We need nulls in programming languages because they are useful to model real-world (lack of) information. All those other clunky techniques will reinvent the same kinds of "null" programming errors!
The orthogonal aspect is making the type system more powerfully aware of nulls so that the compiler sees that possible null conditions were not checked. A compiler error forces the programmer to put in the explicit defensive code to handle the possibility of null values.
- oldandtired 8y agoA correction, there are no "tri-state booleans". Booleans are two state logic systems. Extended Booleans require 2 ^ n states where n is an integer >= 1. Any other number of states automatically ensure that the logic is non-Boolean or non-Extended Boolean.
- jovdg 8y agoI'll just leave this here: https://thedailywtf.com/articles/What_Is_Truth_0x3f_ https://thedailywtf.com/articles/What_Is_Truth_0x3f_
- oldandtired 8y agoBoolean has a specific mathematical/logical meaning and semantics. The moment you add a third state, it is no longer Boolean. The interesting thing is that positive powers of 2 will also allow consistent extended Boolean logic and semantics.
- paulddraper 8y agoCorrect. The real evil is sentinel values. That said, the memory layout of Maybe/Optional (assuming it can be stack allocated) will look much like what you outlined, though of course the API can be more user friendly.
- tathougies 8y ago> That said, the memory layout of Maybe/Optional (assuming it can be stack allocated) will look much like what you outlined, though of course the API can be more user friendly. But it's really not. First of all, most Haskell compilers will optimize away usages of Maybe that are known to be Nothing or Just. Secondly, GHC at least uses tagged pointers for small sum types, including Maybe.
- bjz_ 8y agoRust will do optimisation on the layout of Option-looking data types to simplify them down to a pointer size if possible.
- Zak 8y agoI find it weird that people keep making languages with static typing where all types can also be null instead of using an option type. Doing so nullifies a significant amount of the correctness checking static typing provides. It makes some sense for interoperation when living inside .NET or the JVM, but this was a known problem when those systems were designed.
- danek 8y agoDoing so *nullifies* pun intended?
- davidgay 8y ago1. It's hard to support circular data structures in an imperative language without null pointers. 2. Restricting a language to non-circular data structures will not be popular. 3. Having a nullable and non-nullable version of every pointer or reference type is not usually super popular either. Phrased differently: nullable types are actually a fairly reasonable compromise from a set of not fully appealing choices.
- htgb 8y agoInteresting, I haven't heard this argument before. So what is it about null that makes it more feasible here than for example option types/tagged unions? Also, regarding your third point, IMO the question mark syntax in for example TypeScript and C# is fine.
- annabellish 8y agoWay back when when the JVM/CLR were being originally designed, I'm not sure that Option types as a concept were quite as proven, and both languages were trying to be "safe" languages that didn't have any complicated or new concepts in them. Optional types might not be that now, but they probably were then, when they were strictly in the domain of fairly academic languages.
- ratmice 8y ago
- iteriteratedone 8y agoI would argue that null is perfect for databases ... i expect to get data back or a success call All else is null or an error (table does not exist) If i delete a row with an id that is not present its still a successful query Databases are a special determinance if presistance. A null means you are reading the stored data wrong , your scheme is not an error but its your handling of it , your reading that does not make a deterministic result A null value is like driving a stick shift incorrectly. You are doing something, but what it is , is not clear or producing consistent results
- rosser 8y ago> The essay is conflating 2 different concepts of "null." I'd take it a step further, and posit that The Fine Article's rage comes from its author not grokking the distinction, or even recognizing there is one. Of course null is going to seem frustratingly and dangerously wrong if that's your concept of it.
- tigershark 8y agoNull is dangerously wrong. Languages that avoid it give a much nicer experience because you explicitly write your model considering which values can be missing.
- WillReplyfFood 8y agoOr you write sunny day code and wonder why everyboy elses code is riddled with those strange defensive structures.
- Twisell 8y agoAnd booom you just then reinvented a new concept of "missing" exactly as he said. PS: To disembiguate I was speaking of the null a value in a nullable type. Maybe I got you wrong. Also I guess Null is way less a problem in strictly typed language than in JavaScript for instance.
- tigershark 8y agoI didn’t reinvent anything, the concept of optional value is well ingrained in the real world. If you are registering on a website the email address is mandatory while the home address is optional. If you are sending a parcel the home address is mandatory and the email address is optional. If lazy programmers instead of modelling the optional concept in the type system use a null the result is the huge amount of null pointer exceptions that are riddling a lot of software and the useless “defensive guards” everywhere.
- dragonwriter 8y ago
- robconery 8y agoOP here - I was going to go into that - it's an interesting story. There are null references, as you say, but there's also the null object pattern and the null type. I decided to just focus on the idea of null, which all three of those things represent. A pointer points to a null space, a type represents a value that can optionally be null, and the object pattern allows you to deal with null in your program directly (like Ruby's nil). So... yeah I dig it man :) I just left some things out to keep on a pace.
- SAI_Peregrinus 8y agoI feel like the idea of null is fine, but the implementations are idiosyncratic. Null is an unknown/unknowable/invalid value. You can't know if null = null. This should be an exception or other error. You can't know if 10 = null. Null is unknown. It might be 10, it might not. This should be an exception or other error. You can't have a meaningful result of 10 * null. A pointer to null is meaningless. Languages which lack a way to signify an error other than null can be an issue. Most modern languages have option types and/or exceptions, both of which provide good ways to deal with error conditions.
- Izkata 8y ago> All those other clunky techniques will reinvent the same kinds of "null" programming errors! Worse, instead of blowing up and yelling "this is wrong, fix it!", they'll pretend to work and give you the wrong results. I imagine if null is the "billion dollar mistake", then null never having existed - and relying on sentinels - would've been the trillion dollar mistake.
- wvenable 8y agoMy company uses a very expensive and common accounting software to run the entire business. It uses a sentinel date value that represents no-end-date. That date is 2025-12-31. I suppose in the 80's when the system was first designed they never imagined that the system would still be in use in 2018. There is a slim chance we will have changed software by then but that chance gets smaller every day.
- daveFNbuck 8y agoI imagine businesses plan ahead and make deals for more than 7 years. It's already too late if your sentinel value is within the range of your real values.
- thaumasiotes 8y agoIs it a sentinel value or a sentinel range? There's nothing fundamentally wrong with e.g. having a service begin on May 1st 2028 (2028-05-01) and continue until forever (2025-12-31). The logic will only fail if you assume that 2025-12-31 and all subsequent dates are all equivalently forever. Doing things that way means every time you check the value of a date, the very first check needs to be "is it the sentinel value?". But that's kind of the concept of a sentinel value anyway.
- daveFNbuck 8y agoBut there is something wrong with having some services actually end on 2025-12-31 and other services that are marked as ending on 2025-12-31 because they continue forever. Once 2025-12-31 is in the range of valid end dates, you can't tell the difference between the two.
- tathougies 8y ago> If you invented a theoretical language without logical Nulls, the users of your language would reinvent nulls using worse techniques such as homemade structs with an extra boolean "HasValue" field. Alternatively, you can only use languages which offer actual tagged unions, and avoid the ridiculousness of these 'hasvalue' fields.
- jasode 8y ago>Alternatively, you can only use languages which offer actual tagged unions, I tried to address explicit-null-handling programming concepts such as Option<T> or tagged unions in my last paragraph. Nevertheless, it didn't seem like the essay was about non-nullable concepts but instead, he was writing about the idea of "null" as a data representation for unknown values to be fundamentally flawed because of various boolean operations strangeness. My point is that "null" as a data representation mapping to "missing" is an irreducible complexity which is orthogonal to Option<T>. E.g. F# Option<T> still has ".None" which is a "null by another name". Yes, the programming language support is superior because it forces the programmer to handle possible nulls instead of crashing. Safety around nulls enforced by the compiler is progress. (The null handling as a verb assisted by compiler checks.) However, it didn't remove the need to represent a null as a state -- or null as a noun. Why do I separate those 2 verb-vs-noun concepts? Because he used examples with constants such as "10* null" returning a "null" instead throwing an error as violating math logic. And "10< nil" violating 2-value boolean logic. Therefore he plays with the idea that nulls in the language shouldn't exist. Let's rewrite one of his examples using variables instead of constants: x = Option<int> y = Option<int> x = null y = 10 * x What should "y" be? The essay says that's not the question to ask. He's wondering why multiplication doesn't throw an error. The idea of tagged unions and Option<int> really doesn't address "data" / "mapping" / "noun" concept of null and how it fits into certain intuitions about math and booleans. This irreducible complexity is why "null as noun" will get reinvented as "99999", "-1", etc if you don't have null (whether spelled as ".None", "Nil", or some other standard way). Even if you have an array of Option<int>s and want to serialize to disk, you still need to write "null as data concept" in some fashion (empty string, sentinel value, extra "hasdata" field etc). As side note, I find it interesting that some commenters believe the author is talking about Optional<T> or similar concept and that I missed his point. I ask those readers to look at the essay again and confirm that it makes no mention of "Option", "Optional", "Maybe", "sum types", "tagged unions", etc. His essay seems to be based on the flawed concept of data representation of unknown values. A key sentence near the top: >Logically-speaking, there is no such thing as Null, yet we’ve decided to represent it in our programs.
- sklivvz1971 8y agoTotally agree: further to that, if you had int+bool to represent nullable values, you'd also have to sort the ridiculousness of having a null value with a value, also error prone.
- paulajohnson 8y agoThe point is that option types let you explicitly state which values are nullable, but null references mean that every value is potentially null even if it doesn't make sense.
- pryce 8y agoAnd that having everything being 'implicitly nullable' is a categorically worse for maintainability, readability and comprehensibility than using explicit Option<T> types at the boundaries; such as the implementation in F# [1], with an expressive matching syntax. It is now common when creating a library to rely on manual checking and coders explicitly writing code to check and throw NullArgument exceptions for each object parameter in every public method, and then writing dozens or hundreds more pointless unit tests to ensure this null exception behaviour works as expected; this is totally unnecessary in languages that demand explicitly stated Option<T> when an Option is meaningful. Instead of requiring all the above for safety -an approach which will notably fail to report any errors if the null argument checks are partially or completely omitted- we have -and we should prefer- languages where the compiler or interpreter will not let us pass null into a function where null makes no sense, because that fact is encoded in the function definition. At the library boundaries, which are comparatively rare to internal code, we can simply use the explicit Option type. I should note I have one objeciton with the F# implementation - in that I think that ideally the properties { .IsSome, .IsNone, .Value } should not exist, as they promote bad programming practices. [1] https://fsharpforfunandprofit.com/posts/the-option-type/ https://fsharpforfunandprofit.com/posts/the-option-type/
- rkbjones 8y agoNot for readability. Checking for NULL becomes second nature after programming on a real world C project for a while. I cannot recall the last time I forgot it. On the contrary, I wish C had INT64_INVALID etc., which would facilitate some APIs considerably. Of course that's a dream that would require something like 72-bit words, where one byte is reserved for flags. This would also be a dream for GC flags... Also, since Hoare et al. the tooling has gotten much better. Valgrind catches really almost everything.
- 8y ago
- ddellacosta 8y agoThe Tony Hoare quote is about null _references_ which is about aliases to computer memory. (E.g. the dreaded NPE or null pointer exception.) He's not talking about _logical_ nulls such as "tri-state booleans" or "missing data". I'm struggling to understand what you mean here. My understanding is that there is no distinction between "logical null" and a "null reference" in terms of the problem we're discussing--as soon as you introduce nulls as a placeholder for values that are not yet initialized you have to deal with the logical implications of null being a member of those types, no? It's been a while since I watched the talk, but scanning the transcript from the talk we're discussing (https://www.infoq.com/presentations/Null-References-The-Billion-Dollar-Mistake-Tony-Hoare https://www.infoq.com/presentations/Null-References-The-Bill...) the way Prof. Hoare talks about them seems to be the same in terms of their logical impact on the type system. I quote: 25:55 One of the things you want is to be able to know in a high level language is that when it is created, all of its data structure is initialised. In this case, a null reference can be used to indicate that the data is missing or not known at this time. In fact, it's the only thing that can be assigned if you have a pointer to a particular type. ... 27:40 This led me to suggest that the null value is a member of every type, and a null check is required on every use of that reference variable, and it may be perhaps a billion dollar mistake. And another thing you wrote which I don't understand: We need nulls in programming languages because they are useful to model real-world (lack of) information. All those other clunky techniques will reinvent the same kinds of "null" programming errors! Isn't that exactly backwards? The entire point Prof. Hoare was trying to make is that using nulls to model the "real-world (lack of) information" causes us to have to contend with the logical problems inherent in making null a member of every type. Additionally, sum types seem to model this in a logically consistent way very well, as other commenters have noted.
- tigershark 8y ago> The logic-variant of Null usage for "unknown" "missing" "invalid" values is unavoidable in programming. On the contrary it’s perfectly avoidable. You just need to use an option type with a language that supports comprehensive pattern matching and won’t even compile if you don’t explicitly consider the case of a missing value. If your model is flawed and you don’t want to explicitly specify that some value is optional then the problem is in your way of thinking. And there is no need to invent a language that doesn’t support nulls, they already exist.
- viraptor 8y agoIt's just another name for Null in practice. Or a "typed null" to be more precise. It's got some nice properties, but really it's the good old tri-state. As the op says - is a "logic-variant of Null"
- annabellish 8y agoThat style of "null" has a _lot_ of advantages over the common null found today. The perfect is the enemy of the good - Option/Maybe types aren't perfect, but they're a lot better than null references.
- tomasz_bekas 8y ago>really it's the good old tri-state Yes it is, the point they make is that Option<Boolean> is explicitly tri-state in contrast to regular Boolean which should be two-state.
- dragonwriter 8y ago> It's just another name for Null in practice. No, it's not. > Or a "typed null" to be more precise. To the extent this is true, it is a fundamental difference. > It's got some nice properties, but really it's the good old tri-state. No, it's not. Because the Boolean type contains only True and False, not Null and the Option<Boolean> type (likewise, Option<Option<Boolean>>, etc.) does not contain True or False. There's no weirdness in doing logic operations on an Option<Boolean>, or a pair of them, because it is a type error to attempt it because Option<Boolean> is not Boolean.
- cannam 8y ago> The logic-variant of Null usage for "unknown" "missing" "invalid" values is unavoidable in programming. This is why that null concept shows up repeatedly in different forms such as NaN in floating point, NULL in SQL language, etc As an aside here, there is also a school of thought that NULL in SQL was a mistake, see e.g. https://www.dcs.warwick.ac.uk/~hugh/TTM/Missing-info-without-nulls.pdf https://www.dcs.warwick.ac.uk/~hugh/TTM/Missing-info-without... and http://thethirdmanifesto.com/ http://thethirdmanifesto.com/ (Hugh Darwen and Chris Date)
- prmph 8y agoAnother issue is that the concept of NULL is ill-defined, if you really think about it. There is usually no way to distinguish between use of NULL to represent (1) A missing value, (2) An unknown value, or (3) a default value. These are not trivial distinctions; knowing the semantic intent of a NULL can either hamper or aid in reasoning about a code-base and avoiding subtle errors
- coldtea 8y ago>This is why that null concept shows up repeatedly in different forms such as NaN in floating point, NULL in SQL language, etc. NULL in SQL is also problematic -- e.g. as it behaves wrt aggregations and such. Explicitly user defined unknown values are better.
- noir_lord 8y agoI agree, one of the nicest changes in programming for me is a plugin for intellij and PHP that does static analysis and flags "foo may be be null" via an inspection (it actually does a hell of a lot more than that, truly stellar plug "Enhanced EA Inspections" if anyone has a PHP codebase and uses intellij btw). It catches so many stupid cases where I'd have call bar on foo where foo could be undefined. TypeScript handles it pretty well given the constraints it has to work in.
- flipgimble 8y agoI don’t think it’s conflating anything but trying to explain to you the difference between the two concepts. It’s saying that Null for all references types by default is a bad idea, and representing “missing” in a tagged union (sum type, whatever) leads to better code. Your worry about inconsistent type use for the same concept doesn’t really apply when combined with syntactic sugar for optionals.
- catnaroek 8y agoOptionals are a better alternative to null. They compose better (i.e., they nest) and play nicely with data abstraction (i.e., you can define an abstract type that hides the fact that its underlying representation is optional), unlike null.