[HN Gopher] Null References: The Billion Dollar Mistake ___________________________________________________________________ Null References: The Billion Dollar Mistake Author : wheresvic3 Score : 45 points Date : 2020-01-11 12:55 UTC (10 hours ago) (HTM) web link (www.infoq.com) (TXT) w3m dump (www.infoq.com) | rzwitserloot wrote: | This old chestnut again. | | There is an inherent problem in designing processes and writing | code to capture them: The notion of not-a-value. | | There are great many ways to solve them. The most common ones are | 'null' and 'Optional[T]'. Neither just makes the problem | magically go away. If a process is designed (or a programmer | writes it) thinking that 'ah, well, here, not-a-value cannot | happen', but it can, then.. you have a bug. | | Some language features might make it possible to help reduce how | often it occurs, but eliminate it? I don't think so. | | Imagine, for example, in an Optional based language, that you | just map the optional to a lambda to execute on the optional, and | the behaviour of the optional is to then simply silently do | nothing if it's optional.none. That'd be a much harder to find | bug than a nullpointer error. (errors with stack traces pointing | at the problem are obviously vastly superior to mysterious do- | nothing behaviour with no logs or traces of any sort!). | | Some other creative solutions: | | * [Pony](https://www.ponylang.io/) tries to be very careful about | registering when an object is 'valid' and when it isn't, and when | you write code, you have to say which state the objects you | interact with can be in. This lets you avoid a lot of the | issues... but pony is quite experimental. | | * In java you can annotate any usage of a type with nullity info, | and then compiler linter tools will simply tell you that you have | failed to take into account a potential null value. You are then | free to ignore these warnings if you're just writing test code, | or know better. Avoids clogging up the works with optional, but | as the java ecosystem shows, you can't just snap your fingers and | make 30 years of massive community effort instantaneously | instantly be festooned with 'might-not-hold-a-value' style | information. At least the annotation style gives the hope of | being backwards compatible (to be clear, optional, for java? | Really bad idea). | | * in ObjC, if you send a message to a null pointer, it silently | does nothing, in contrast to virtually all other languages with | null types where attempting to message a null ref causes an error | or even a core dump. | | * Just write better APIs. Have objects that represent blank state | (empty strings, empty collections, perhaps dummy streams which | provide no bytes / elements, etc). For example, in java: Java's | map (a dictionary implementation) has the `.get(key)` method | which returns the value associated with that key, and returns | `null` if there is no such value. About 6 years ago another | method was added in a backwards compatible fashion (so, all java | map implementations got this automatically): `getOrDefault(key, | defaultValue)`. This one returns the provided default value if | key isn't in the map. You'd think optionals provide a general | mechanism for this, but, in scala, you have both: There's | `someMap get(key)` which returns an optional, so to get the 'give | me a default value' behaviour, that'd be | `someMap.get(key).getOrElse(defaultValue)`, but maps in scala | also have the java shortcut: `someMap.getOrElse(key, | defaultValue)`. Sufficient thought in your APIs mostly obviates | the issues. | | null is not a milion dollar mistake. It is a solution to an | intrinsic problem with advantages and disadvantages over other | solutions. | melling wrote: | I remember tracking down the null silent message failure issue | in the early 1990s on NextStep. Then again almost 2 decades | later on the iPhone. Personally, I'm not a fan of silent | failures. | | IMHO, allowing for non-nullable variables is a huge improvement | in language design. Adding boilerplate annotations is an ugly | way to handle it. Optimize for the common case and make | variables non-nullable by default. | strictfp wrote: | In my experience, forbidding null refs usually only results | in getting null objects instead, such as empty strings or | empty collections. Thats not bad, but might not solve such a | silent error message, you'll still end up with an empty | message in the end. In order to solve it proper, I'm thinking | you'd might want to go further and have more expressive type | constraints, like Ada subranges. | temac wrote: | The mistake is being nullable/optional by "default", that is | with the least amount of effort for programmers using such a | language. Or worse only ever nullable (like Java is except for | its built-in scalars I think?). | | There is obviously a need about having optional things, but | this is not the common case, so this should not be the default | and even less the only solution. And it should enforce handling | the absent case. | | "null" is a shortcut for talking about solution which does | nothing of that (and is even UB in case of mistake in some | languages). Billion Dollar Mistake is generously low; probably | the cost is already _Multi_ -Billion Dollar, and counting. | JoshMcguigan wrote: | The goal of `Optional[T]` is not to "make the problem magically | go away", in fact that is almost the opposite of the goal. | | Optional[T] exists to make it very obvious when a value is | nullable. Having non-nullable types as default, with | Optional[T], allows a developer to model a system more | accurately. This is helpful both to the compiler as well as | anyone else who reads/maintains that code. | | > Imagine, for example, in an Optional based language, that you | just map the optional to a lambda to execute on the optional, | and the behaviour of the optional is to then simply silently do | nothing if it's optional.none. That'd be a much harder to find | bug than a nullpointer error. (errors with stack traces | pointing at the problem are obviously vastly superior to | mysterious do-nothing behaviour with no logs or traces of any | sort!). | | This is just one of the things a developer could decide to do | when faced with an optional which is none. It is up the | language design to make it easy to express this behavior (or | any other behavior they might choose) without hiding it. | agumonkey wrote: | Not contradicting, just that there a slight benefit in | reifying an issue as it opens for notation and operators to | simplify it. Maybe monad or option chaining are more than | making the thing obvious, it make them half disappear. | strictfp wrote: | Sure it's up to the language design, but in practice a `None` | gets a similar treatment as an empty collection, usually | effectively short-circuiting remaining calculations. As the | parent poster pointed out, this might either be the behavior | you want, or actually mask the error, depending on the | situation. By this logic, optionals aren't better than null | refs, just different. The same argumentation holds for | exceptions vs optionals. | JoshMcguigan wrote: | In my experience, languages with strict non-null guarantees | (and optional types), do the exact opposite of "mask the | error". If anything, they are sometimes faulted for being | too verbose. | | The idea is, by explicitly marking things which can be null | (wrapping them in an Option[T], for example), you can be | sure that everything else is not null. This alone relieves | the developer of a large cognitive load. | | Further, the language can provide syntax to make handling | optional types obvious without being painful. Rust match | statements are one example of this. | | Can you provide a specific example of how using an optional | type makes a potential "missing-thing" type of bug harder | to see? | kerkeslager wrote: | > There are great many ways to solve them. The most common ones | are 'null' and 'Optional[T]'. Neither just makes the problem | magically go away. If a process is designed (or a programmer | writes it) thinking that 'ah, well, here, not-a-value cannot | happen', but it can, then.. you have a bug. | | > Some language features might make it possible to help reduce | how often it occurs, but eliminate it? I don't think so. | | On the contrary, you can 100% eliminate it by forcing null | handling at compile time with your `Optional` type. Haskell and | some other strongly-typed languages do this (but they call it | Maybe). | | The way to do this in a C-syntax-ish language would look | something like this: Optional<int> | increment(Optional<int> i) { // return i + 1; would | throw an error at compile time, // because Optional | doesn't implement the + operator // | i.applyToValue would throw an error at compile time | // if you didn't handle both possible cases return | i.applyToValue( ifNull: (void) => { return new | Optional<int>(null); }, ifValue: (int i) => { | return i + 1; } ); } | | This is syntactically a bit heavy, partly because I was a bit | more verbose than a real implementation would need to be, for | clarity, and partly because C-style syntax doesn't do this | well. Languages that support this generally have some syntactic | sugar to make it a bit more terse. | | I've argued before on HN that the benefits of strong static | typing are overstated, but this is a case where strong static | types really do completely eliminate an entire category of | errors. Given how common these errors are, not using stronger | types in this situation for popular languages has absolutely | been a billion dollar mistake. | masklinn wrote: | > Haskell and some other strongly-typed languages do this | (but they call it Maybe). | | Most call it either Option or Optional FWIW. `Maybe` is the | term used by Haskell and its derivatives (like Idris or Elm). | twic wrote: | > Imagine, for example, in an Optional based language, that you | just map the optional to a lambda to execute on the optional, | and the behaviour of the optional is to then simply silently do | nothing if it's optional.none. That'd be a much harder to find | bug than a nullpointer error. | | It's worth noting that this is only possible if the operation | you're mapping over the optional can have side-effects. Without | side-effects, mapping over an optional _always_ does nothing, | in a way - all the difference is in the value returned. | | Adding that constraint does make programming pretty painful, | though. | olliej wrote: | Null termination is still easily much worse. At least the general | case of null dereferences today (less so earlier) is a page | fault. | agumonkey wrote: | Should every domain have a Nil element instead ? | loopz wrote: | What is required is an optional "No" element. Then you can say, | I have a "No" Problem, and people will think you're joking and | remain on their happy path. | fhars wrote: | No, obviously not. Every domain having a Nil element is exactly | the problem null references have introduced (at least for the | call by reference parts of the affected languages). | agumonkey wrote: | Null is a single nil for all, I meant having a null per | domain would force people to think of what it means to have | nothing in that field and handle it. Maybe I'm too naive. | augusto2112 wrote: | Sometimes you don't want to allow a value to be null at | all, but with null references you can't represent that at | the language level. | agumonkey wrote: | But for numbers, a zero is not considered null, because | it was handled in the operators rules. | fhars wrote: | Numerical zero has nothing to do with the issue discussed | here. What you are proposing is to add another "number" | to types like int and float that results in the program | crashing whenever you try to add it to another number. | agumonkey wrote: | I think it does | strictfp wrote: | It does! It's the numerical "null object", just like the | empty string and empty collection. | masklinn wrote: | > I meant having a null per domain would force people to | think of what it means to have nothing in that field and | handle it. | | In what way would it change anything? The "billion dollars | mistake" is that because "nothing" is part of every type, | any value you get could really be missing, and you have to | either hope for the best (and die like the rest) or program | ridiculously defensively. | | Having a magical sentinel per type would have the exact | same issue, namely that "nothing" is part of the type | itself, and so you can never be sure at compile time that | you do have "something". | | That's what opt-in nullability (whether through option | types or language builtins or a hybrid) changes, by default | if you're told you have an A it can _only_ be a valid A, | and if you 're told you _might_ have an A you _must_ either | check for it or use "missing-safe" operations. | erik_seaberg wrote: | This is one of Go's weirdest features. When you cast nil to | an interface, you pay for extra storage so the runtime can | do method dispatch on what type of object you _don 't | have_, even though every implementation is likely to panic | immediately. | seventh-chord wrote: | "Making everything a reference: The Billion Dollar Mistake" is | the talk I want to see | dorfsmay wrote: | Everything in Python is a reference, and there's no null | pointer issues. | brudgers wrote: | Everything in Python is an object. In Python, containers are | objects that reference other objects. | | https://docs.python.org/3/reference/datamodel.html | | https://docs.python.org/2.0/ref/objects.html | auxym wrote: | I've certainly had some "None" errors in Python. | | I think the difference comes from dynamic vs static typing. | In Python, you sort of get into the habit of "defensive" | programming: checking inputs to your function, catching | Nones, etc. | | In java, you tend to rely more on the type system. If it | typechecks/compiles, there's a good chance it's OK. That is, | until you get a null value that's not handled. | | That's the root issue I think: If null is an acceptable value | per the type, then the same type system should force you to | handle it. As do the type systems in ML languages for option | types, for example. | JakobProgsch wrote: | The first line is why I'm not 100% convinced of the | severity of this mistake compared to the alternatives. The | problem fundamentally is the use of magic values/numbers to | represent the concept of "no value". You don't need | explicit language support to have that concept and the bugs | it causes. I guess having that as an intrinsic concept in | the language makes it more likely that people use it badly. | On the other hand debuggers etc. also intrinsically | understand this and segfaults due to null pointers are | usually very easy to localize once you see them. On the | other hand if a "bad programmer" introduced their own magic | non-value in a supposedly safe language, debugging that | becomes way more confusing. | andrepd wrote: | No, that's not the "fundamental problem". The fundamental | problem is a type system that lies. A "pointer to string" | is not actually a pointer to a string, it's a pointer to | a string _or to nothing_. If your api returns a pointer | of the latter type, it should signal this by making the | return type "maybe-pointer to string" (although it has | the same memory representation as "pointer to string"). | Then, if the user tries to dereference a maybe-pointer | (that is, to use a maybe-pointer as a pointer), the type | system can statically catch this and make it a simple | type check failure compilation error. The user must first | check if it's null through a function that casts a maybe- | pointer to a pointer. | | Nothing about this precludes the usage of sentinel | values. | kragen wrote: | You may be interested in http://canonical.org/~kragen/memory- | models then. I don't think it's necessarily a _mistake_ but it | 's definitely taken for granted far too much. | x3ro wrote: | Can you elaborate? I can't remember the last time I thought "oh | darn it why is this a reference", but I can think of a billion | problems I've had with nulls in jvm languages | emsy wrote: | Cache incoherency, which will cost us more and more | performance as CPUs will improve slower in the future. | gameswithgo wrote: | there are a few completely different ways to interpret this, | can you explain? | seventh-chord wrote: | in languages like c, rust or go, where you can put arbitrary | data on the stack, it seems to me as if such issues are less | common because you dont have to worry about initializing | pointers and allocating memory unless you actually want to | put something on the heap. Thus if you make everything a | reference in your language its no wonder you run into issues | like null-pointers more often | DaiPlusPlus wrote: | With stack allocation you then encounter problems with | object lifetime. Rust solves this problem by binding | references to scope, and Go solves this by invisibility | changing an allocation to the heap (and uses ref-counting? | I think?). | | I wish C had a feature that would let you allocate | something on the stack and then return to the parent stack | frame without popping the stack-pointer - that would be | handy for self-contained object-constructors. | zozbot234 wrote: | Go uses fully-general GC, not reference counting. | Obligate reference counting is used in other languages | such as Swift, probably with worse throughput than | obligate tracing GC. | cm2187 wrote: | Plus also doesn't the stack need to be small to fit into | the CPU cache? | seventh-chord wrote: | There is absolutely no requirement from the hardware that | the stack be any particular size | DaiPlusPlus wrote: | On the Windows desktop, the default stack size is 1MB. In | IIS-hosted applications the default stack size is reduced | to 250KB due to the popularity of the now-outdated | programming trope of "one thread per request (per- | connection)". On x86 Linux the default stack size is 2MB | - which seems generous. | cm2187 wrote: | I am not thinking requirement by rather performance wise. | giulianob wrote: | Regardless of whether it's on the stack or heap the point | still stands. If all your objects are randomly allocated | then an array is just references to those objects and | will start out null. If you're using value types then | your array of objects will never be null (empty instead) | and you will benefit from CPU caching the data. | x3ro wrote: | This comes up again and again in one form or the other, yet new | languages still seem to be making the same mistake. Of all | languages I've touched, Rust seems to be the only one that mostly | circumvents this problem. Are there other good examples? | deepaksurti wrote: | Swift with optional and optional chaining. [1] | | [1] https://docs.swift.org/swift- | book/LanguageGuide/OptionalChai... | zozbot234 wrote: | > Rust seems to be the only one that mostly circumvents this | problem. | | The Rust hype is getting ridiculous here. There are plenty of | languages with non-nullable references as first-class, and | optionals for the nullable case. | | (...And I say this as a Rust fan myself, for what it's worth.) | samatman wrote: | This comment would be much improved with a list of those | languages. | | Kotlin and Swift come to mind, what are others? | kragen wrote: | If we're limiting ourselves only to new languages, then | nulls are statically excluded not only by Kotlin and | Apple's imitation of it, Swift, but also by F#, Agda, | Idris, and (sort of) Scala. But the zozbot didn't seem to | be talking only about new languages, so Haskell, Miranda, | Clean, ML, SML, Caml, Caml-Light, and OCaml are also fair | game. (It wouldn't be hard to list another dozen in that | vein.) Moreover I think you could sort of make a case for | languages like Prolog and Aardappel where you don't have a | static type system at all, much less one that could | potentially rule out nils, but in which the consequences of | an unexpected nil can be much less severe than in | traditional imperative and functional languages like Java, | Lua, Python, Clojure, Smalltalk, or Erlang, which more or | less need to crash or viralize the nil in those cases. | amelius wrote: | Imho, Rust is an awkward language because it positions itself | as a systems language but it makes low-level stuff more | difficult (there's even a book teaching how to implement | doubly linked lists in Rust [1]), hence prone to mistakes. At | the same time, people are using Rust to build non-systems | programs, where other languages would be more appropriate | (e.g. those with garbage collectors). I don't think it is a | good idea that Rust is promoted as the language that will | rule them all; in my opinion, it is still a research | language. | | Linus Torvalds said the following about Rust [2]: | | [What do you think of the projects currently underway to | develop OS kernels in languages like Rust (touted for having | built-in safeties that C does not)?] | | > That's not a new phenomenon at all. We've had the system | people who used Modula-2 or Ada, and I have to say Rust looks | a lot better than either of those two disasters. | | > I'm not convinced about Rust for an OS kernel (there's a | lot more to system programming than the kernel, though), but | at the same time there is no question that C has a lot of | limitations. | | [1] https://rust-unofficial.github.io/too-many-lists/ | | [2] https://www.infoworld.com/article/3109150/linux- | at-25-linus-... | zozbot234 wrote: | > there's even a book teaching how to implement doubly | linked lists in Rust [1] | | Doubly-linked lists are an awkward example because the | "safety" of a doubly-linked list as a data structure | involves fairly complex invariants that Rust can't even | keep track of at this point, much less check independently. | These things are exactly why the unsafe{} escape-hatch | exists and is actively supported. But just looking at the | _amount_ of unsafe code in common Rust projects should | suffice to figure out that this is not the common case, at | all. | | > At the same time, people are using Rust to build non- | systems programs, where other languages would be more | appropriate (e.g. those with garbage collectors). | | Garbage collectors are good for one thing, and one thing | only: keeping track of complex, spaghetti-like reference | graphs where cycles, etc. can arise, perhaps even as a side | effect of, say, implementing some concurrency-related | pattern. Everything else is most likely better dealt with | by a Rust-like system with _optional_ support for reference | counted data. | | That's without even mentioning the _other_ advantages that | a Rust-like ownership system provides over a GC-only | language. See e.g. | https://llogiq.github.io/2020/01/10/rustvsgc.html this | recent post for some nice examples. | pkulak wrote: | Kotlin | progval wrote: | > Rust seems to be the only one that mostly circumvents this | problem. Are there other good examples? | | Rust is not the first one to have an Option type; it's a common | feature of functional languages because they have ADTs ( | https://en.wikipedia.org/wiki/Algebraic_data_type ) | masklinn wrote: | > Rust seems to be the only one that mostly circumvents this | problem. Are there other good examples? | | Swift, Kotlin, and of course older languages of a functional | bend like MLs, Haskell, Idris, Scala, ... | | Some are also attempting to move away from nullable references | (e.g. C#), though that is obviously a difficult task to perform | without extremely severe disruptions. | the_alchemist wrote: | Scala happily accepts null as it is the bottom type for | AnyRef and needed for jvm compatibility. Kotlin has a | compiler check that enforces it, Scala does not. | gmartres wrote: | It's coming to Scala too: | https://dotty.epfl.ch/docs/reference/other-new- | features/expl... | rubyn00bie wrote: | I really love(d) Scala for introducing me to the whole | idea of Optionals. | | I wish for the life of me I felt like I could approach | Scala at a time when it wasn't going through huge flux (I | have shitty luck). I spent a good amount of time pre- | version 2.10 :( and then recently went to have a look but | saw Dotty (version 3.0?) coming by the end of 2020 and I | was like "well, FML, time to wait a few more years and | try again." | | Anyone have any tips for using the Scala ecosystem | effectively these days? Should I just wait for 3.0? Is it | going to be a long winding road of breaking changes until | a "3.11" version? | | Is there a good resource for what folks are using it for | these days? It seems like all the projects I used to know | are ghostly on Github (but that could also be the fact it | has been quite a few years, heh). Or do most folks just | pony-up and use plain ol' Java libraries while writing | their application/business logic in Scala? | augusto2112 wrote: | Functional programming languages have been doing it for ages. | Most "newer" statically typed languages also have it (Swift, | Kotlin, Rust) by default. And old languages had it bolted on | (C# 8, Java 8, C++ 17). | | I think at this point basically everyone has realized null by | default is a terrible idea. | masklinn wrote: | > And old languages had it bolted on (C# 8, Java 8, C++ 17). | | C#: actually true, you can switch over to non-nullable | reference types | | Java 8: meeeh, it provides an Optional but all references are | still nullable, including references to Optional. There are | also @Nullable and @NotNull annotations but they're also meh, | plus some checkers handle them oddly[0] | | C++17: you can deref' an std::optional, it's completely | legal, and it's an UB if the optional is empty. Despite its | name, _std::optional is not a type-safety feature_ , its goal | is not to provide for "nullable references" (that's a | pointer), it's to provide a stack-allocated smart pointer | (rather than have to allocate with unique_ptr for instance). | | [0] https://checkerframework.org/manual/#findbugs-nullable | gameswithgo wrote: | rust, f#, ocaml, latest version of c# has an option to sort of | get rid of nulls, zig | hawkice wrote: | Haskell, notoriously. I believe it pioneered the ergonomics of | the alternatives used elsewhere. | cmrdporcupine wrote: | AFAIK Standard ML predates Haskell and it has an option type. | dunefox wrote: | ML is even older than SML and has algebraic data types. | davidgay wrote: | The reason they come up again and again is that it's hard to | design an imperative language without them (try, assuming you | want to provide generic user-defined data structures that allow | for cycles). | | As a result, calling them a "mistake" is reasonably dishonest, | as it implies there was an obvious, better alternative. | jrockway wrote: | I assume two reasons, efficiency and because an efficient | implementation of mutable state would have the same problem. | | Right now, a single sentinel value makes a pointer null or not | null (0x0 is null, everything else is not null). This is | exactly how you'd implement a stricter type, like "Maybe". | Encoded as a 64-bit integer, "Nothing" would be represented as | 0x00000000 and "Just foo" would be represented as 0xfoo. No | object may be stored at the sentinel value, 0x00000000. Exactly | the same as what we have now, and provides no assurances that | 0xfoo is actually a valid object. | | Meanwhile, Haskell which "doesn't have null" crashes for | exactly the same reason your non-Haskell program crashes with a | null pointer exception: f :: Num a => Maybe a | -> Maybe a f (Just x) = Just (x + 41) | | This blows up at runtime when you call f Nothing, because f | Nothing is defined as "bottom", which crashes the program when | evaluated. | | It's exactly the same as langages with null pointers: | func f(x *int) *int { result := *x + 41 | return &result } | | And the solution is the same, your linter or whatever has to | tell you "hey maybe you should implement the Nothing case" or | "hey maybe you should check the null pointer". | | Where I'm going with this is that you need to develop entirely | new datatypes and have an even stricter type system than | Haskell. Maybe Rust is doing this, but it's hard. We all know | null is a problem, but calling null something else doesn't make | the problems go away. | anderskaseorg wrote: | > It's exactly the same as langages with null pointers: | | Four huge differences: | | 1. You don't need to pass around 'Maybe a' everywhere. If | null isn't expected as a possible value (which usually it | isn't), you just pass around 'a', and when you do use 'Maybe' | it actually means something. | | 2. The Haskell compiler can, and does (with -Wall), tell you | that your pattern match is non-exhaustive. You don't need a | separate "linter or whatever". This is possible because the | needed information is present in the type system, and doesn't | need to be recovered with a complicated and incomplete static | analysis pass. | | 3. If you do this anyway, the error is thrown at exactly the | point where 'Maybe a' is pattern-matched, not at some random | point several function calls later where your null has | already been coerced into an 'a'. | | 4. This program is defined to throw an error; it's not | undefined behavior like in C that could result in something | weird and unpredictable happening later (or earlier!). | | Also, Rust optimizes away the tag bit of 'Option' under | common circumstances; for example, 'None: Option<&T>' (an | optional reference to 'T') is represented internally as just | a null pointer, which is safe because '&T' cannot be null. | jrockway wrote: | > You don't need to pass around 'Maybe a' everywhere. | | You don't need to pass pointers around everywhere. | Languages with null still have value types that cannot be | null. | | > You don't need a separate "linter or whatever". | | Optional compiler flags count as "whatever" to me. | | > it's not undefined behavior like in C that could result | in something weird and unpredictable happening later (or | earlier!) | | C++ doesn't define this, but the OS does (and even has help | from the CPU). | | Anyway, my TL;DR is that it's easy to have a slow program | that passes everything by value, or east to have a fast | program that uses pointers or references. Removing the | special case of null is meaningless, because you can still | have a pointer to 0x1 which is just as bad as 0x0, | probably. This goes back to my original answer to the | question "why don't more languages get rid of null" which | was "it's harder than it looks." I think I'm right about | that. If it were easy, everyone would be doing it. | temac wrote: | > Languages with null still have value types that cannot | be null. | | Not all languages. | | > C++ doesn't define this, but the OS does (and even has | help from the CPU). | | That's not how it works anymore, because C / C++ front- | ends interacting with the optimizers are yielding too | "optimized" results. See the classic | https://t.co/mGmNEQidBT | tibbe wrote: | This missed the point. The point of not that you can forget | to check the null case. The point is that you can express | that sometimes there's no null case. | jrockway wrote: | The "no null" case in traditional languages is just "int" | instead of "*int". All values inside an "int" are valid | integers. | | Certainly it's problematic to use the same language | primitive to mean "a pointer" and "this might be empty", | but it's what people use them for in every language that | has pointers (that I've used anyway). | dunefox wrote: | That's not the same thing as a null pointer because Nothing | isn't allowed in place of e.g. integers, strings, etc. like | in Java. What you're doing is defining a non-total function. | Haskell, per default, doesn't perform exhaustivity checks | when pattern matching, but you can enable that via a compiler | flag - then it won't let you compile your example. Ocaml, for | example, does that by default. | [deleted] | RickJWagner wrote: | No comment on the Null References, but I will say I _love_ the | time-index provided for the video. I wish every video had these! ___________________________________________________________________ (page generated 2020-01-11 23:00 UTC)