40 ms·
The Logical Disaster of Null
- skywhopper 8y agoI disagree with the author here, and while I admit that Null failures are a pain, it's not true to say they don't exist in other languages. "Maybe" and "Option" etc may force you to deal with them before they will compile, but that's not the same thing as saying the concept of Null does not exist in those languages. I'm sure there are some languages out there without any concept of Null, but they would have their own shortcomings for the lack of it. It's also wrong to suggest that Null has no place in "logic". Boolean logic is one type of logic, but it's not the only type. Finally, the examples of how Null works in various languages are really poor. "Why doesn't Ruby coerce nil into zero?" Because it doesn't coerce any types implicitly. Why should nil be the exception? How is that expectation "logical"?
- anthony_romeo 8y agoThis was my initial thought reading this post, that logic has developed quite a bit the past few thousand years, with different logics able to evaluate different types of values (e.g. Kleene's logic). But I feel the author's better point is that different languages evaluate unknown/null/nil/none values differently, or in an illogical way. Like, ideally if a language were to use a null value, I feel that such a value shouldn't ever evaluate to, say, 0 or an empty set, because it's making an unwarranted assumption.
- setr 8y agoI remember this insight from a paper on SQL's 3VL issues (true/false/null), and I think it somewhat apllies to nulls issues inanguages; its a 3VL logic system that doesn't go all the way. Sometimes it gets forced into 2VL semantics (conditionals), and the conversion is where all the problems lie. If it stayed true to its word, and fully embraced 3VL, there wouldn't be an issue.
- gowld 8y agoMaybe/Option aren't Null. They don't crash when you to perform type-checkingly valid operations, unless your language allows you to write partial functions. And you aren't required to wrap a type in Maybe/Option the way that languages require you to admin Null into every (non-primitive) type. Obviously "nothingness" exists and needs representation. The problem with Null is that it's not part of the type system but is part of the program, so it undermines the value of having a type system.
- taeric 8y agoI've seen programs that crash given a none. Often explicitly called out with a message saying that a value must be supplied. So, a good thing in those cases. I'm not optimistic enough to think it would always be a good thing, though. I've actually seen some where the lack of a value was not noticed because people just mapped over the optional and did not code for the missing case. Effectively coercing the value to whatever the zero was. Now, I can't claim empirically that these would outnumber null pointers. I just also can't claim they don't exist.
- fiddlerwoaroof 8y agoYeah, I have this intuition that options create there own horde of problems because of the way that map/<$> propagate None so that, once you get an unexpected None, it becomes harder to trace the source of the problem. A null pointer exception or segfat, on the other hand, will give you a stack trace or similar that will help you pinpoint the source of the problem.
- flipgimble 8y agoI think you misunderstood something about the languages mentioned like Swift or Haskell. They do have a way to represent the concept of "nothing", or "missing" using an enumeration (called Optional in Swift, Maybe in Haskell). What they don't have is the global concept of Null that sits at the root of the type hierarchy. This means every type in a language like C# or Javascript has to have Null as one of its members. If you want to define some operators/functions on the members of the type, have have to always consider Null as a member. Like the author listed: How do you compare Null, how do you negate Null? Those questions shouldn't even be asked because Null is not negatable or comparable. Maybe the problem is that Null shouldn't have been admitted as member of a type that you consider comparable or negatable. So in Swift/Haskell, when you define a type you don't consider "nothing" as one of its members. The mental model in Null-using-languages is that a Type is a sort of blueprint that can be stamped out to make instances of that type. From that point of view its natural to consider you may be missing an instance. In language like Swift or Haskell the concept of a Type is closer to a set in math; in this case the set of all possible values of that type. This is why I said above that Null has to be considered as a member of a type. I’m using math language to re-interpret the type-as-blueprint world view, to show why it leads to illogical results. Seriously, Swift demoting of the concept of “nothing” to just another enum is alone worth the price of admission. This has cascading consequences that lead to safer code. You also get simpler code as you strive to resolve the uncertainty of a missing value as early as possible in your code. Swift is the most impressive language I've seen in a while, but think its origins at Apple have overshadowed the its incredible technical value.
- yxhuvud 8y agoHave you used any language that has a type system powerful enough to support arbitrary sumtypes (and also has null as a separate type)? If not then I can recommend playing around some with Crystal. IMO optimals are just a crutch to make up for a too weak type system.
- annabellish 8y agoGiven a sufficiently powerful type system, you should still err towards an Option type, because you don't want to have to make two types for everything you want to represent - the real type, and the real type but also null. Having an Option type lets you compose that behaviour, even if, yes, it's as simple to define as `type Maybe x = Just x | Nothing`.
- robconery 8y ago>it's not true to say they don't exist in other languages Sounds good, waiting for an example to support this... >It's also wrong to suggest that Null has no place in "logic". Boolean logic is one type of logic, but it's not the only type. What other types did you have in mind? Given that we work as programmers in a world defined by true/false 1/0 logic, I think you might want to reconsider this blanket dismissal.
- philwelch 8y agoThere are a lot of three-valued logics that lots of programming languages implicitly follow by accident sometimes. For example: true || 3 ==3 || panic() will, through short-circuiting, evaluate to “true” even though the final element doesn’t evaluate to either true or false. (As you may observe, they also follow a weird logic where AND and OR are not commutative...)
- DonbunEf7 8y agoYou seem intelligent, so I'm going to drop you into the deep end. In category theory, a topos [0][1] (plural topoi) is a structure-place where logic can be done. Boolean logic corresponds to a particular topos. Actually, there are at least two topoi which do Boolean logic; one of them has the law of excluded middle, and another has the axiom of choice. [2] And there's an infinite other number of topoi to choose from! Topoi can be custom-made to categorical specifications. We can insist that there are three truth values, and then we can use a topos construction to determine what the resulting logical connectives look like. [3] Finally, there are logical systems which are too weak to have topoi. These are the fragments, things like regular logic [4] or Presburger arithmetic. To address your second argument, why do we work in a world with Boolean logic? Well, classical computers are Boolean. Why? Because we invented classical computing in a time where Boolean logic was the dominant logic, and it fits together well with information and signal theory, and most importantly because we discovered a not-quite-magical method for cooking rocks in a specific way which creates a highly-compact semiconductor-powered transistor-laden computer. Computers could be non-Boolean. If you think that the brain is a creative computer, then the brain's model of computation is undeniably physical and non-classical. It's possible, just different. Oh, and even if Boolean logic is the way of the world, does that really mean that all propositions are true or false? Gödel, Turing, Quine, etc. would have a word with you! [0] https://en.wikipedia.org/wiki/Topos#Elementary_topoi_(topoi_in_logic) https://en.wikipedia.org/wiki/Topos#Elementary_topoi_(topoi_... [1] https://ncatlab.org/nlab/show/topos https://ncatlab.org/nlab/show/topos [2] https://ncatlab.org/nlab/show/two-valued+logic https://ncatlab.org/nlab/show/two-valued+logic [3] https://toposblog.org/2018/01/15/some-simple-examples/ https://toposblog.org/2018/01/15/some-simple-examples/ [4] https://arxiv.org/abs/1706.00526 https://arxiv.org/abs/1706.00526
- Izkata 8y ago> Finally, the examples of how Null works in various languages are really poor. "Why doesn't Ruby coerce nil into zero?" Because it doesn't coerce any types implicitly. Why should nil be the exception? How is that expectation "logical"? That was exactly what I would've guessed with those examples, even without knowing Ruby. Likewise, C# being the one where things "get strange", especially after Javascript? From the example, the C# version acts really close to NaN - a "this is unknown" value that contaminates whatever it touches. I'd call C# and Ruby equally logical, with different intentions, given the examples.
- jcranmer 8y agoThere's one key difference between null as it applies to languages like C and Java versus Option<T>-like renditions of null: null doesn't infect the type-system in the latter. Type systems can be viewed as a lattice, usually as a bounded lattice. If you look at Java's reference type system (ignore primitive types), there is a top type, aka Object. There is also a bottom type. It doesn't have a name you can spell, but it does have a single value--null. This means that null can satisfy any type, even if the type is impossible to satisfy--and as a result, there is an unsoundness in Java's type system.
- ian1321 8y agoDo you still feel the same way if you consider the option type a container type.
- NegativeLatency 8y agoUnrelated to the discussion of null: Ruby the language might not coerce types, but the standard library will happily do things like multiply a string by a number, or parse a malformed date resulting in garbage.
- pera 8y agoHaskell have the Maybe monad, which is defined as Just a | Nothing. One may argue then that languages with nullable integers implicitly define this type as Maybe Int.
- Retra 8y agoWell, that just pushes the goalposts of the complaint: now Haskell has Int, and those other languages do not.
- pera 8y agoI meant that in some way one could think of, for instance, C's int as a sum type of just integer and null :) in practice the obvious difference is that a language like Haskell enforce considering both options with its type checker.
- AnimalMuppet 8y agoNo, you can't think of C's int that way - it doesn't have a null.
- pera 8y agoYou are completely right, not sure where my head was :P
- Peaker 8y agoThat's the Maybe type. The Maybe monad is this: instance Monad Maybe where return = Just Nothing >>= _ = Nothing Just x >>= f = f x (And is not really related to the discussion)
- pera 8y agoRight! that definition was the type, thanks for the correction :) still, the Maybe monad is used for computations that may fail, which is often the purpose of the null pointer.
- barrkel 8y agoC# has (a subset of) SQL null semantics because of LINQ. That's the answer to his specific question. Null values propagating through expressions SQL style is an approach to handling unknown values. Whether it's desirable is somewhat besides the point; databases have null values, and LINQ enables capturing expression trees that get converted into SQL, so keeping similar semantics makes a kind of logical sense. Nulls are undesirable in a language until you want to initialise large structures in a simple language with a simple compiler. Staying away from the temptation then takes ingenuity and discipline.
- bobbyi_settv 8y agoWas the behavior of null with integers really changed when LINQ was added? What would his examples have done in C# 1.0?
- hprotagonist 8y agoThese laws apply to logical expressions about things that exist. In other words: you can’t apply these laws to the unknown, which also includes the future. This is where we arrive at the edge of the rabbit hole: null represents nothingness/unknownness, so what the hell is it doing in a deterministic system of 1s and 0s? Computer systems are purely logical, but the applications that we write, if they embrace Nulls, are apparently not. Null is neither true nor false, though it can be coerced through a truthy operation, so it violates Identity and Contradiction. It also violates Excluded Middle for the same reason. So why is it even there? And suddenly a bunch of type theorists just winced. It is possible to have trivalent logic that's coherent. SQL does this -- and it makes sense to do it in that application.
- mjburgess 8y agoI really don't like throwing the word "pseudo-intellectual" around because its mostly used to mean "I think I'm smarter than you". However, this person begins their article poisoning the well, saying, > I find that the people I talk to about this instantly flip on the condescension switch and try to mansplain this shit to me as if. Proceeds to speak in that very same condescending tone, presenting a smarter-than-thou trundle down from the mountain. All the while including some nonesense about logic. This person clearly has a chip on their shoulder: tacking on things about community-regulation in an article about Null, like all technical public engagement authors do. Let's signal "what good behaviour we expect" in the midst of a book pitch and a confused discussion of a technical matter. One of these goals can be failed in its attempt with good nature. When you smush all this together it seems an exercise in performative intellectualism, or more accurately, pseudo-intellectualism.
- deleted 8y ago[deleted]
- zeth___ 8y agoYou can easily have n-valued logics. Saying they don't work because Aristotle didn't use them is like throwing out Newtons laws because Aristotle didn't use them. There have been whole schools of mathematics that reject the law of the excluded middle: https://en.wikipedia.org/wiki/Constructivism_(mathematics) https://en.wikipedia.org/wiki/Constructivism_(mathematics) Newer logics also don't use that law but instead deal with undecidability, which is less than a century old but is the most import result in logic since it's invention.
- Animats 8y agoC++ would be a lot better off if references were used more heavily. (And C ought to have references by now.) One still sees too many asterisks in C++ code. References are not supposed to be null. Sometimes they are, though, because there's no checking when a pointer is converted to a reference. "this" should have been a reference, not a pointer. Strostrup admits that was a mistake.
- FartyMcFarter 8y agoPointers are easier to read than non-const references though (since they're more explicit).
- gpderetta 8y agotechnically references can't be null ever. To create a null reference you would have to deference a null pointer and then you are into nasal demons territory. /pendantic
- benjohnson 8y agoWhat I'd like to tell the author. Don't like null? Don't use it.. and you find null propagation ruining your abstraction then treat it as an error and fix your program.
- evocatus 8y agoPerhaps possible in isolation or on a small team. I don't think this is practically achievable on teams that have grown past a certain size, though. To paraphrase Carmack, "Any syntactically valid code, that the compiler will accept, will eventually make it into your code base." [1] [1] https://www.youtube.com/watch?v=Uooh0Y9fC_M https://www.youtube.com/watch?v=Uooh0Y9fC_M
- AstralStorm 8y agoNot if you review your code reasonably well and use static analysis plus some testing, making it a process to not get bad code into your codebase.
- occamrazor 8y agoAt some point one will include external libraries, written with different styles and standards. And then will modify the libraries, making them effectively part of the core code base.
- mamcx 8y agoSo, no use any OS, library or code-base on top of C, C++, Java, .NET, Javascript, Sql...???
- klodolph 8y agoIt actually turns out that there are better ways of solving problems with null that don't involve just telling programmers to go fix their programs. There are alternatives, like encoding whether a value can be NULL (or some semantic equivalent) into the type system. Rust and Haskell are examples of languages where this is the only way to do things, and C# and TypeScript are examples of languages where you can selectively (and under certain condutions) make distinctions between values which can be null and which cannot be null.
- camdenreslink 8y agoThe functional paradigm answer to this is to have an Option<T> type, or Result<TSuccess, TFailure>, which allow you to flexibly account for the “null case” while still having total functions (https://en.m.wikipedia.org/wiki/Total_functional_programming https://en.m.wikipedia.org/wiki/Total_functional_programming). The only catch, is now you have to unwrap your function results somehow (functional languages provide ways to do that, like the scary monad). I like this website, which demonstrates the concept: https://fsharpforfunandprofit.com/rop/ https://fsharpforfunandprofit.com/rop/
- barrkel 8y agoOption monads have the same semantics as C# null described in the article; they don't apply the function if the value isn't present, you get another non-present value back out. Result<,> has the same semantics as checked exceptions, BTW. The conversion between the two representations of code is mechanical. Checked exceptions are a poor idea the more dynamically bound your language is, and are generally anti-abstraction in any case (failure modes are implementation specific, i.e. non-conformant with an information hiding interface). An error result is only useful if you can make a decision based on the specific value; that's not the case for almost all sources of error in most user (i.e. non-system) programs, where complete coverage of error cases with specific handlers is outside their design parameters, and termination (of program or request or whatever) is preferable.
- camdenreslink 8y agoIt’s about the ability to reason about the code. Option types force matching expressions whenever you encounter the wrapped value, forcing the developer to handle the failure case. Equivalent C# code is to add checks for nulls all over the place, aka “defensive coding”. C# has an Option type sort of with nullable types, but they are for value types only, and developers can still reach in and just grab the value, eliminating the safety that option types provide.
- contingencies 8y agoIt's about leaky abstractions. If programming is about managing complexity and status is ideally specified explicitly, then null is simply the option in a mathematical set defining that status which corresponds to the option commonly seen on surveys: Other (please specify): ... While it can be handy to have this 'extra value' in a set, and it is most commonly used to denote special meanings within a carefully controlled context (eg. SQL column in a result set is empty, a variable is of no type - ie. not defined at all, etc.), issues arise when people accidentally carry context or presumptions about the meaning of null across contexts, creating a leaky abstraction. Most of the author's article appears to deal with differences in these context-specific assumptions. Perhaps the Java approach: throw an exception. Unix approach? Nonzero return values and arbitrary stream or file data to clarify. In edge-case leakiness, very similar to the Java approach. The functional and dedicated non-OO procedural programming approach: define exit parameters to your function, specifying complete precision and ending any ambiguity. Since a type is a formal context (set), then using a typed language is another solution, although that adds overhead it brings benefits in rigor. Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function. - John Carmack
- jstewartmobile 8y agoSomeone needs to write an essay on the productivity disaster of "considered harmful" essays. We traded goto for callback hell and ten-layer inheritance hierarchies. A null-purge would probably end similarly.
- baking 8y agoAs a programmer with assembly language in my blood, all I can think is "Why should I care that this silly person thinks 'zero' doesn't exist?"
- maxk42 8y agoIt's not that 'zero' doesn't exist. It's that in assembly Null's just a zero.
- draw_down 8y agoSometimes you make a mistake, and something you told the computer would be there is not actually there. That’s a fundamental problem, there is no getting around it. You can call it something besides “null” if you like; the thing will still be missing and you’re gonna crash, sorry. Optionals just force you to consider the case when the thing doesn’t exist, which is nice if you’re trying to please a compiler I suppose. The problem is still there, even if you do a little dance about it.
- robobro 8y ago> Aristotle was the only logician and if you point me towards Buddhist or Daoist philosophy, you're mansplaining! OP should check out trinary logic and first-order predicate calculus. Just because OP doesn't appreciate "null" doesn't mean that it should be removed from programming languages or from existing programs.... false means not true, zero means no things, null means absence.
- robconery 8y agoOP here - OP has checked out (and lived with) trinary logic. Just because you appreciate null doesn't mean it should be kept in programming languages and existing programs. That there is a logical truism, isn't this fun? Also: false means not true, zero is a number and null doesn't exist, by definition. We can model true/false/zero easily as they exist. Null is made up, so every language gets to think about what it means in an abstract made up way. Thus the pain, thus the post.
- zeth___ 8y agoThe last 100 years have been dealing with the fact that true and false are not enough to describe the world of computation. You also need undecidable, or null, for statements that can be proved to never terminate. It is very much still an open question if a statement is absolutely undecidable and if we need to add something like null in all logic [0]. As for your arguments on why we don't need null, they sound exactly like the arguments against zero from the middle ages [1]. >Just as the rag doll wanted to be an eagle, the donkey a lion and the monkey a queen, the zero put on airs and pretended to be a digit. [0] http://logic.harvard.edu/koellner/QAU_reprint.pdf http://logic.harvard.edu/koellner/QAU_reprint.pdf [1] Menninger, Karl (1969), Number Words and Number Symbols. Cambridge, Mass.: The M.I.T. Press.
- tigershark 8y agoMaybe instead you should check out the languages that make life easier without the null abomination?
- hamstercat 8y agoIf anyone wants to see for themselves what life is without null, TypeScript has an option to type-check for possible null/undefined values with strictNullChecks[0]. It's a game changer. The con: you have to check every variable that could be null/undefined before using it. The pro: you have to check every variable that could be null/undefined before using it :) [0] https://basarat.gitbooks.io/typescript/docs/options/strictNullChecks.html https://basarat.gitbooks.io/typescript/docs/options/strictNu...
- mushishi 8y agoOur stack is Typescript and Kotlin, and I find handling of null simple and safe, especially in Kotlin there is decent supporting functionality https://kotlinlang.org/docs/reference/null-safety.html https://kotlinlang.org/docs/reference/null-safety.html With Java we used @NotNull annotations and IDE support to give warnings. Luckily we are converting our legacy code base to Kotlin. With conditional type conditions Typescript will have better support than earlier: type NonNullable<T> = Diff<T, null | undefined>; // Remove null and undefined from T Source and the examples in: https://github.com/Microsoft/TypeScript/pull/21316 https://github.com/Microsoft/TypeScript/pull/21316
- mattbierner 8y agoJust a followup point: for new TypeScript projects, strongly consider using the “strict” compiler flag. This flag enables strict null checks along with a number of other useful checks / restrictions, such as disallowing variables without known types from being treated as “any”. These checks will catch bugs and improve your code but trying to enable them after the fact can be painful
- mirimir 8y agoI have no clue why coding languages need null. I mean, they're deterministic, right? If something is missing, undefined or whatever, that's an error. What does the null concept gain you? In data, on the other hand, null is a very useful concept. It explicitly means that there is no value in a field. And that prevents such mischief as interpreting missing data as zeros.
- millstone 8y agoIn a language like C, NULL solves problems that are otherwise awkward to solve. 1. What should `malloc()` return on failure? 2. How should I indicate that I don't care about certain out parameters, e.g. the parameter to `time()`? 3. How should I initialize variables that are going to be used as out parameters, e.g. in `strtol()`? Other languages address these at the cost of significantly complicating their type system and ABI: generics, multiple return values, etc. In a language intended to be small like C, I'm not sure how you can do better.
- mirimir 8y agoThanks. But ... 1. Why not just return meaningful values? Wouldn't that help in debugging? 2) ??? 3) That makes sense to me.
- AlotOfReading 8y agoC functions can only return one value. Since the stdlib generally adheres to the idea of minimizing overhead, that would mean malloc would have to accept a mutable reference to a reference, so it could assign the reference it returns. Since null references are unusable, using that impossible value as your error flag is a pretty clever optimization.
- mirimir 8y agoThanks, I see that. But isn't ambiguity the tradeoff?
- 8y ago
- chrisoverzero 8y ago> No one seems to know why C# behaves the way it does. Operators are lifted[0] over nullability in C#. Every value type T can be converted implicitly to Nullable<T>. When `10 * null` is typechecked, both sides of * are typed as Nullable<T>. The * operator then acts like the pseudo-Haskell (*) <$> 10 <*> null or, I guess liftA2 (*) (Just 10) Nothing The semantics of Nullable<T> are similar to those of an optional type, with some implicit mapping and lifting. In that context, null acts less like null. (Thanks to convenient conversions.) Note that the following doesn't throw: int? value = null; value.HasValue // == false [0]: https://blogs.msdn.microsoft.com/ericlippert/2007/06/27/what-exactly-does-lifted-mean/ https://blogs.msdn.microsoft.com/ericlippert/2007/06/27/what...
- juliangoldsmith 8y agoI came here to write this. What C# does in this case makes sense if you take the time to pick apart what it's actually doing.
- deleted 8y ago[deleted]
- 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 ago
- kllrnohj 8y agoSurprised there's no mention of Kotlin here. It handles this really nicely, forcing you to declare if a value can be null and if it is null it requires a null check before it can be used (with some syntax sugar to make that cleaner)
- pabl0rg 8y agoKotlin solves this problem nicely, assuming your codebase is all new or has been annotated with @Nullable/@NotNull https://kotlinlang.org/docs/reference/null-safety.html https://kotlinlang.org/docs/reference/null-safety.html
- tigershark 8y agoIt doesn’t seem that nice to me compared to making it impossible to assign nulls everywhere, without the need of annotating anything.
- Zak 8y ago> This leads to an inconsistency: if to_i will turn nil into a 0, why won’t that coercion happen when trying to multiply? Because Ruby doesn't automatically coerce arbitrary types to numbers when you try to perform arithmetic on them. This is a Good Thing. 2 * "4" > TypeError 2 * "4".to_i > 8 Interestingly, it is possible to multiply a string by a number, but no coercion takes place. "2" * 4 > "2222"
- robconery 8y agoOP here - Yes that's the operation the question wasn't supposed to be a literal one, rather a consistency issue, which illustrates the larger point that different languages deal with null differently because it's not logical and therefore confusing and a pain in the ass :)
- Zak 8y agoLanguages are definitely not consistent in what they do if you try to coerce null to various types, nor are they consistent (often even internally) about whether they perform coercions implicitly. The Ruby example seemed to deal mostly with the latter. I think implicit coercion is bad, but that's a separate issue from null.
- decebalus1 8y agoI always found this[0] analogy quite accurate whenever I discussed this issue with others. Setting aside how different languages (mis)treat null as a concept, I think the whole discussion is about convoluting boolean logic with memory addresses and some languages do a better/worse job at being 'intuitive' than others. I had great success with this[1] whenever I felt things were going in the wrong direction or when the language constructs of dealing with nulls were in the way of the domain design. [0] https://www.b4x.com/android/forum/attachments/unbenannt-jpg.54095/ https://www.b4x.com/android/forum/attachments/unbenannt-jpg.... [1] https://en.wikipedia.org/wiki/Null_object_pattern https://en.wikipedia.org/wiki/Null_object_pattern
- paulhodge 8y agoI have a pet peeve whenever people bring up the old "Billion dollar mistake" quote. Calling it a mistake means that it could have been avoided. But we couldn't have avoided null pointer errors (or some other name for the same thing) any more than humans could have avoided the bronze age. In the 60s and 70s we didn't have the "technology" to avoid null errors. By technology I mean production-ready languages with a static typing layer sophisticated enough to implement a Maybe/Optional type. Those languages weren't production ready until maybe around the 80s. And most of those compilers were themselves implemented in unsafe-null languages like C. But anyway, that's history, now we have nice languages that have safe nulls, so the interesting questions moving forward are: why are people still creating new languages that have unsafe nulls (looking at you Go), and why are people still choosing to use languages with unsafe nulls?
- wvenable 8y agoThe real billion dollar mistake was nullable references in Java and C#. By then we should have known these things need an extra type-specifier. But Java was meant to be simple and easy. References in C++ are non-nullable so the precedent already existed. I hope C# gets around to solving this problem -- Microsoft is working on it -- but it's much harder to retroactively solve it.
- zvrba 8y ago> References in C++ are non-nullable so the precedent already existed. Wrong analogy. References in C++ are not first-class entities. Conceptually, they're _alias names_ for existing objects. Unlike C# and Java "references", you cannot "reset" a C++ reference to "point" to another object. Because it's not a pointer. It does not "point". It's an alias. `void f(int& ref)` in C++ is the same as `void f(ref int x)` in C# (the equivalent doesn't exist in java). Inside `f`, you cannot change `x` to "point to some other int" because it's not a pointer! C# and Java "references" are semantically the same as C++ pointers minus arithmetic.
- AstralStorm 8y agoYes, C++ can have nonnullable smart pointers just fine if that is what you want. They will lose reset call, throw on assigning null T*, static assert on nullptr_t, require full initialization on construction, have maximum exception safety. This could've been done since 2003 but wasn't. There are attempts to bring it into language as part of C++ Core Guidelines project. This is possible because unlike Java and C# not everything can be null.
- gwbas1c 8y agoC# has null because all new memory is initialized as all zeros. The constraint is that any object or struct needs to be valid if it's in-memory content is all zero. Thus, null must be supported for object references because the pointer has to support zero. Value types can work without null because 0 is valid. Could the language designers implement object types without null? It would be very difficult for fields, especially in structs, because it's nearly impossible to force memory initialization. You couldn't do "default (StructType)" if it had a not null object as a field.
- wvenable 8y agoIt would be nice if C# simply had a nullable type for reference types. So like int? you could also have string? or SomeClass?. Structs with non-nullable reference types would have to be initialized at creation time. This would solve a lot of errors. But you still need to have the option to have nullable references.
- tuna-piano 8y agoIn an integer column in a relational database, what is the alternative of having null? 0 is not an option, as that will return incorrect mean/median calculations. So what would be there? Or am I misunderstanding?
- deleted 8y ago[deleted]
- oldandtired 8y agoIf there is missing data to occur within a column, then pragmatically, you split that column off into its own table with the associated key from the original and store only those keys that have valid values. If you do anything else, such as using nulls, then you are just creating a problem that WILL come back and bite you in the nether regions of your psyche. Of course, there will other opinions about how to handle this. As far as I am concerned, Nulls are a curse foisted on us by those vendors and standards bodies who took the the easy way out.
- bvrmn 8y ago> you split that column off into its own table with the associated key from the original and store only those keys that have valid values. That will create real problems and bite you immediately.
- oldandtired 8y agoDemonstrate that it will bite you immediately. This technique has ensured that only valid data has been kept and that reporting works. When nulls are stored there are no guarantees that anything you ask of the database will ever turn out right. Especially when there are millions of records stored. Two queries that should give you the same answer give different results when nulls exist. Seen it too often.
- bvrmn 8y agoTable separation leads to record fragmentation and big IO cost on record fetching. Your ideal academic world will be crashed under production reality. "Millions of records". Bwa-ha-ha.
- _bxg1 8y agoI think this opinion makes some sense from a pure-functional standpoint, but not from an imperative one. In imperative programming, where you're managing lots of state, it's important to be able to represent the concept of a slot with nothing in it. That said, I think a large portion of the problems caused by null could have been avoided by making one small change to its behavior: accessing a member (or element) of a null should evaluate to null instead of throwing. This is deeply intuitive and is the biggest cause of null pointer exceptions. If you try to access a.b, and a is null, it makes perfect sense that b is also null. Many languages have recently started adding an "optional chaining" operator that works this way, but a lot of pain could've been avoided if things were this way from the start.
- agsamek 8y agoI would extend on this idea. Whenever exception were to be thrown we could result in null instead. We would end up with error-free programs instantly. Good luck looking for root cause of strange results.
- _bxg1 8y agoNote that I didn't suggest this for method calls, only for property access. Again, it's extremely intuitive that a nothing's property is nothing. Making that logical extension is not sweeping errors under the rug, it's dovetailing them into a format where they can be implicitly handled by logic that already exists. I.e., if(a != null && a.b != null && a.b.c != null) becomes if(a.b.c != null). It doesn't make the problem go away, but it certainly mitigates it.
- agsamek 8y agoFair point. This might be a trade off for instant error reporting / ease of exception handling. I would strongly forbid any coersion of null to other values if this idea was to be implemented.
- Chyzwar 8y agoYou need to throw when and b is a method. Solution to the problem is already there: Kotlin, TypeScript, Rust, Crystal, Swift, Haskell just to name few. We just need to push the industry toward better and safer languages. We keep building an abstractions on top of unsafe languages and then we are suprised that it suck.
- sklivvz1971 8y agoClearly there's a place for null: most languages have it, most developers have no problem with it, it does represent something (lack of information). It is logical and mathematical--I suggest you read the GEB book for tons of more info on that. That said, people are _also_ free to experiment with null-free languages, or to avoid null. If it works for their use case, fantastic! Just the attitude of the post is terrible. For example the user creates a sock puppet and posts a trolling/edgy question to Stack Overflow... just to see if it's toxic. Sorry, these posts are toxic, in my opinion.
- _bxg1 8y agoYeah, it was super weird how the subject migrated from programming theory to a rant about stack overflow. On the actual topic, I think a good compromise is what typescript and I think rust do, which is, a value is only nullable if you explicitly declare it as such. It forces you to be judicious, while still allowing you the option when you need it.
- sklivvz1971 8y agoI've been trying that, but so far I don't find a big advantage, but it _is_ a bit annoying to have to annotate all types that could be null. This is to say: it could be good, or it could be another "exceptions in Java" moment
- FilWisher 8y agoI don't mean to defend Null. > Null is neither true nor false, though it can be coerced through a truthy operation, so it violates Identity and Contradiction. It also violates Excluded Middle for the same reason. Intuitionistic logic doesn't have the law of excluded middle and is the form of logic underlying the simply-typed lambda calculus. There is a more nuanced relationship between logic and programming languages than is being discussed here.
- threepipeproblm 8y agoUnknowns are not even remotely problematic for logic. Not only SQL, but illustrious languages such as VB6, include built-in trivalent logic.
- ErwinSmout 8y agoYeah and the results are so massively intuitive.
- threepipeproblm 8y agoI suppose this is sarcasm but the results are quite intuitive to me. From my perspective, it's trivial to construct the truth tables for trivalent logic based on a sense of what "should" be in them. Maybe give it a try.
- ErwinSmout 8y agoWell guess what. Your "sense" of what "should" be in them has no place in computer SCIENCE. Computer SCIENCE is that ugly thing that tells us that three-valued logic gives rise to 19683 distinct binary logical operators, while two-valued has 16. Computer SCIENCE is that ugly thing that tells us that if you want a computer language over a three-valued logic to be expressively complete, then you need to implement all of those 19683 logical binary operators one way or another. In the worst case, that's 19683 operator names for the programmer to remember. And you come here claiming that it's "trivial" because you have a "sense" of what the results ought to be ? That proves just one thing but site policy probably won't allow me to spell that out. (In case you were wondering what the 16 names are in two-valued logic : they aren't needed because the system being two-valued gives rise to certain symmetries that gracefully allow us to reduce the set we need to remember to just {AND OR NOT} (or some such) which beautifully parallels the way we communicate in everyday life.)
- threepipeproblm 8y agoAh, you seem to be a bit nutters. So I'm not going to engage further but I do want to give you a serious response to the argument you seem to be making. First, the same argument above is also an argument that, say, integers, are not "Computer SCIENCE". More to the point, you might enjoy reading the work of Charles Pierce and other logicians of that era who began to explore many variations on formal logic. Note that just as many operations arise from trinary relations in bivalent logic. Are binary relations "Computer SCIENCE", but not trinary or higher relations? Before you answer, you might want to look into whether all possible relations can be expressed using only binary relations (hint: nope). Look deeper into the concept of functional completeness (with respect to a subset of operators), which you reference above without naming. You might be able to understand how many of those many trivalent operators are actually necessary to reason with (hint: not very many, hardly more than for bivalent logic, where, as you note, we only tend to use a few, and need not worry about it). Consider also the relationship between operators folks have identified as useful in bivalent vs trivalent logic (hint: they not picking at random). Could it be that just as with the 16 binary operators, many of which have relations to one another (e.g. inverses and complements, among others) that the trinary operators could fall into similar groups, which, making the 3^9 number you mentioned seem a whole lot less complex? Could that be why it's neither necessary nor customary to work with all the operators in either sort of logic? Once you've caught up to state of the art in formal logic as of the 1930's you might have a new perspective -- perhaps you might even begin to let us know when "Computer SCIENCE" will catch up!
- thedancollins 8y agoAwesome. A thread about null. Has anyone called somebody else "Hitler" for disagreeing with their opinion yet?
- deleted 8y ago[deleted]
- Guthur 8y agoThis was a decent post until he went on the stack overflow rant.
- vemv 8y agoNull/nil tends to represent the absence of a thing. That's perfectly logical. Things can be absent.
- _Codemonkeyism 8y agoI've been coding since around 1981. What changed my coding style most, is Option when I've started Scala 10y ago.
- mavdi 8y agoScala is a very confused language and specially about the use of Options vs null. I find that Rust and Swift enforce Options a lot better.
- amelius 8y agoEven if you eradicate Null, programmers will create a singleton object to represent it.
- Xuper 8y agoYeah, just like they invented Unit/Void singleton in functional languages.
- deleted 8y ago[deleted]
- deleted 8y ago[deleted]
- YeGoblynQueenne 8y ago>> Logically-speaking, there is no such thing as Null (...) Oh but there is. The author is probably considering only propositional calculi with two truth values, such as Boolean algebra and, er, well, they're probably only considering Boolean algebra because that's what we use in computers, because it maps nicely to 0s and 1s. However, two-valued logics are by no means the only possible logics, neither are they the only ones that have actually been described in the framework of mathematical logic. Probably the most well-known many-valued logics are Łukasiewicz's and Kleene's that have three truth values (i.e. values assigned to literals): true, false ...and unknown. ... which is to say, "null". And just to blow your mind, there are also infinite-valued logics, like fuzzy logic and, I'd argue, the good old probability calculus of the reverend Bayes, which is nothing if not a many-valued logic. The mistake is, I think, that the author is taking "logic" to mean Aristotelian logic, however that is not at all the logic we use in computers. Like I say above, computers use Boolean algebra which is an entirely different formal system with its own axioms, separate to grandpa Aristotle's own. For instance- Aristotle never said anything about functions, mappings from the set of literals to {0,1}, neither did he formally define the algebra of the Boolean operators AND, OR and NOT (a.k.a. conjunction, disjunction and negation). Although you can project Aristotelian logic onto Boolean logic, they are far from the same and I would really struggle to see how one would implement a programmable computer using Aristotelian logic. P.S. Am I mansplaining now? Wouldn't that be a little ...weird?
- WkndTriathlete 8y ago>> Kleene's that have three truth values (i.e. values assigned to literals): true, false ...and unknown. ... which is to say, "null". Regardless of what logics exist the statement you make - that "unknown" is "null" - is actually wrong and the heart of the problem. "Unknown" is only one semantic interpretation of null; there are many others, and problems arise in software development because of those (sometimes slight) differences in the interpretation of what "null" should reflect in the real world. Some sources suggest as many as 129 possible semantic meanings for "null", which is why Date rails against "null" values in SQL. With Option/Maybe we're constrained to the universe of values of that type plus exactly one more value (None); with null who knows how many of the 129 possible meanings of the null value we are dealing with in addition to the base type? Null is computationally and mentally expensive to deal with.
- jeandejean 8y agoI like the fact that the author says: "don't be complacent and mansplain your feelings about null", but that is exactly what he does... People claiming the industry is wrong and that we should use some logically pure language are usually impractical and deny the compromise that must be made for systems to be usable by the masses.
- TheCoelacanth 8y agoA language does not need to be logically pure to avoid null. Having null in a modern language is simply a boneheaded mistake. There are no compromises that need to be made to get rid of it. Optional types are superior in every way.
- he0001 8y agoHow are they superior?
- combatentropy 8y ago> Logically speaking, there is no such thing as Null Yes, there is: "Did you pass your test?" "I haven't taken it yet." "Okay, will you pass it?" "Null." Suppose there was a database table of students, with a column called "passed," which is boolean. If it's in the middle of the semester, that column must be null. True means they passed. False is put there when they fail. --- Another example, in a table of help tickets, suppose there is a timestamp field called "closed," for when the ticket was closed. If the ticket is open, then that column must be null. --- "Which show is currently playing on channel 3?" "It's just static. It's midnight, and channel 3 has stopped broadcasting." (This of course must have been back in the '80s.) If the TV guide were a database table, with time slots for each channel, then the columns for which show is scheduled for midnight on channel 3 must be null. In fact, that's how I picture null: ever-shifting static inside the little cell in my database table. That's why I'm fine with how if you ask if two null values equal, the answer is null (at least in Postgres). Someone may say that there is a show currently on channel 3, and the name of the show is "Static." But that's not quite true. If channel 3 recorded static and broadcast it, then yes. But channel 3 has literally turned off its tower. It is broadcasting nothing. Your TV is showing static because you tuned to a station that is not there. --- The writer complains about inconsistent implementations of null, like in JavaScript. I agree that there are misimplementations. I would not have had both null and undefined. In fact, that's another way of understanding what null is. Suppose you say my earlier examples with SQL are flawed, because SQL is flawed, because it insists on every row having columns it doesn't need, that the field for "passed" should even exist in that row until the class is over. Say instead you were using objects. Within the semester it may look like this: { name: "Edgar Smith" } Then at the end you add: { name: "Edgar Smith", passed: true } Well, what if you asked for the value of student.passed in the middle of the semester? You might say it is a mistake, but it is a question that can be grammatically formed: "What is the value of the 'passed' key in the object?" The only answer is null. To me null often means "not applicable." --- Again, another example. In school we played a game of guess-the-object, where you could ask only yes-or-no questions. There were three possible answers: yes, no, or "does not compute." Clearly the answer of "does not compute" was needed for when the answer was neither yes or no. "Does not compute" was a fancy synonym for "null." --- Null is the answer to the infamous loaded question, "When did you stop beating your wife?" --- Null is quantum foam. It is what is happening at the base of the universe, if you look close enough. Is the particle here or there? Null. You may say that doesn't make sense, that it's just that we don't have the right instruments. But that is Quantum Mechanics. If you wish to disprove Quantum Mechanics, Einstein and I would both be interested, as he was uneasy with it too. But going after quantum mechanics would be a better use of your time than going after null. Right now, null and the scientific consensus about physical reality agree.
- dshoemaker 8y agoHow is it possibly mansplaining to respond to this with an opinion or alternate explanation? Also... isn't the other's gender fairly important to the mansplaining comment since the term references the phenomenon of women being explained things they already know?
- mjburgess 8y agoWhen a man is condescended to by other men we call that "communication", when a woman is its called "mansplaining".
- speedplane 8y agoIs "null" really the problem, or is not knowing the state of something the problem? I agree that it would be better for the world if we always knew what a "thing" was or referenced, but more often than not, we don't. Having a construct that expresses this uncertainty nicely models our own uncertainty.