11 ms·
Null References: The Billion Dollar Mistake – Tony Hoare (2009) [video]
- elchief 10y agoYou're gonna need nulls until databases stop supporting nulls. And everyone would need to use 6th normal form for that to happen, and nobody wants that
- danielnixon 10y agoNot true. Nullable values in a database can be dealt with (and I would argue _should_ be dealt with) using a maybe/option[1] type. This is exactly what Slick[2] does, for example. [1] https://en.wikipedia.org/wiki/Option_type https://en.wikipedia.org/wiki/Option_type [2] http://slick.lightbend.com/ http://slick.lightbend.com/
- bubaflub 10y agoCould you explain why you believe the presence of a NULL in the database necessitates a NULL pointer somewhere in the code?
- andrewguenther 10y agoI believe the author's intent is if you read a null value out of a database, how would you represent it in code?
- deleted 10y ago[deleted]
- bubaflub 10y agoI think it depends on where the NULL is and what it represents. If NULL value is in a field that is used for JOIN-ing, I don't think you would "represent" the NULL value as much as you would simply have a lack of data. For example, if you had some set of results from a query that contained a JOIN on a field and some values were NULL, those records with the NULL value would not be in the result set. If we do receive results with possibly NULL values I believe they could be either be represented with an appropriate zero value -- e.g. "" or 0 -- or with an optional type like another commenter suggested.
- IncRnd 10y agoNull references to memory are what is being discussed, which is completely different from variant/option types. Changing databases has nothing to do with NULL references to memory.
- bbcbasic 10y ago.NET uses DBNull.Value, which is not null. Also 6th normal form?? What is that?
- lgas 10y agoYou store each letter in the names of the columns of your tables in a different data center.
- icebraining 10y agohttps://en.wikipedia.org/wiki/Sixth_normal_form https://en.wikipedia.org/wiki/Sixth_normal_form Not something I'd like to use.
- achr2 10y agoI work with an engineering application that uses a 5th/6th normal form database that is implemented in standard SQL server/Oracle DBs. It is awful and painful. A simple query with maybe five properties and 2 relationships takes upwards of 20 joins. Yet the database only has 4 tables...
- meddlepal 10y agoThe problem isn't null itself, but that many languages use nullable types by default. Null is a damn useful construct and while there may be better solutions to using a null reference they're often not as clear as using null or worth the time investment to develop properly. So yea, I generally try to avoid null's and completely understand how they've caused a lot of problems, but I'm not willing to say we shouldn't have them or use them when appropriate.
- kazagistar 10y agoYou don't just not use nulls, you replace them with something like Optionals. With a bit of language support, they can compile down to nulls but provide a layer of type safety and convenience functions.
- kmiroslav 10y agoIt's perfectly fine to use nulls in languages that encode them in their type system, e.g. Kotlin.
- junke 10y agoExactly. The problem is not that there is a null, it is that it is a valid value for all types (e.g. you can pass null to a function that expects a String). Allowing nulls explicitly, like with a "String?" type, is the way to go in languages where Option is not an option.
- kqr 10y agoIsn't it, in practise, basically the same thing though? The theoretical difference is this: 1. Option is a regular data type/object that represents "a collection of at most one value". It's similar to a list, set, heap, tree or whatever other collection types you have, except it can not contain more than one value. 2. With explicit nulls I guess any data type (e.g. Integer) will automatically get a clone of itself (a different type named Integer?) where also null is a valid member. From a purely theoretical standpoint, I like #1 better.
- randiantech 10y agoJust to add my two cents to the discussion, Typescript is implementing Non nullable types [1]. I think i'd be convenient that any language being used for large projects would support this feature. [1] https://github.com/Microsoft/TypeScript/pull/7140 https://github.com/Microsoft/TypeScript/pull/7140
- kaeluka 10y agoSome functional language use non-nullable types by default. Haskell, ML, OCaml, f.ex. Java has the checker framework that supports `@Nullable` annotations and will allow only those vars/fields to contain `null`.
- SuddsMcDuff 10y agoI posted a very closely related article about this last year (http://mattdavey.logdown.com/posts/259807-avoiding-the-billion-dollar-mistake http://mattdavey.logdown.com/posts/259807-avoiding-the-billi...) - it's C# focused but the idea should carry over to similar languages. It summarizes 5 strategies for dealing with nulls, rather than just jumping straight into monads.
- deleted 10y ago[deleted]
- ppcsf 10y agoI think the section dealing with the Optional monad sort of glosses over their composability, which is one of the primary reasons we use monads. Multiple functions that all return an optional can be composed; for instance, if we had Optional<WidgetFriend> GetWidgetFriend(Widget widget) and WidgetFriend had an Optional<FriendName> property, we could simply write [1] from widget in _widgetRepository.FindById(widgetId) from friend in _widgetRepository.GetWidgetFriend(widget) from name in friend.Name select name; and get an Optional<FriendName>, without having to repeat all the tedious pattern matching of Some or None for every call. If any of those calls returns a None, the entire evaluation short-circuits and we get a None result at the end. Of course, we can still write Optional<Widget> widget = null; which is the problem with not fixing this issue on a language level. [1] You'd have to implement Select and SelectMany, instead of Map and Bind, to get query syntax like this.
- achr2 10y agoI think you'd like C#'s linq syntax and null coalesce operator. While obviously they don't get away from null, they go a long way to making this type of syntax and null safety much easier to implement.
- deleted 10y ago[deleted]
- Perceptes 10y agoOne of my absolute favorite things about Rust is that nulls can't be used to circumvent the type system. They must be explicitly accounted for via an option type in all cases. It's very hard to go back to a language that doesn't do this after getting used to it. I get so frustrated by constant null dereference errors when that entire category of error can be avoided.
- ArkyBeagle 10y agoI'd rather have explicit seperation of concern for UB-causing behavior than have a generic monad approach. Perhaps the examples I've seen in Rust just don't do that, because part of the appeal of Rust is that you sort of don't have to. That makes the cognitive load acceptable and documents all the UB prevention in source code. It's a habit arrived at from using formal instantiation protocols that were driven from external to the device being made - starting with RFC1695.
- skoczymroczny 10y agoWhy are option types that force you to check the value for null good, but checked exceptions are frowned upon?
- danielbarla 10y agoThe difference is that currently, there's no way to express "this (reference type) variable really cannot be null", which makes it painful. It's the equivalent of having "throws Exception" on every method, declared for you implicitly.
- Sharlin 10y agoCurrently in some (well, unfortunately many) languages. C++ references have always been non-nullable, and in Scala the only way you should get nulls is from Java libraries.
- asQuirreL 10y agoParent means something closer to pointers (in C++) when they say "reference type". In other words, if a type contains null, then we must always check locally that values of that type are not null before it is safe to use them (or manually maintain contracts). With option types, we check whether it is empty once, and if it is not, we unwrap it and use it as if it were never nullable. Any function that uses the unwrapped value downstream is oblivious to the fact.
- adrianratnapala 10y agoC++ references can easily be null (T& foo = *ptr_i_thought_was_good;). But they provide a useful social convention: if it is a pointer then it is your job to check for NULL. If it is a reference, then it is the job of the other guy to ensure it is not null. And the rules of the language mean that null references (as opposed to pointers) are rare.
- shultays 10y agoNot without an UB
- chvid 10y agoNulls are not a mistake. They are a trade-off as so many other things in language design.
- virtualized 10y agoBenefits of nullable by default: - Drawbacks: numerous How is this a trade-off?
- chvid 10y agoNull as a default is useful / a big simplification when it comes to reflection/meta-programming. Consider this piece of pseudo-Java/Spring code and think how you would do it if the platform you were using forced you to either declare a and b as optional (which they are not) or assign them some value between the IoC container instantiates the class X and wires the values for a and b. public class X { @Autowired ServiceA a; @Autowired ServiceB b; @PostConstruct void init() { // a and b are instantiated by the IoC container and // are fully valid for the rest of the execution } }
- ppcsf 10y agoConstructor injection?
- chvid 10y agoYes. But then you have to define an explicit constructor. Also X maybe auto wired into ServiceA or B making it impossible for the IoC container to create the intended object graph without splitting construction and injection into two passes.
- yazaddaruvala 10y ago1. Lombok @RequiredArgsConstructor? 2. Do you not consider cyclic dependence a code smell? At least I have always avoided cyclic dependencies.
- igravious 10y agoSo that's the famous Tony Hoare. Nice trip down memory lane there. Who was the guy at the end from the Erlang community? (The one who drew a chart with the axes useful/useless versus unsafe/safe that he claimed he got from Simon Peyton-Jones?)
- bogomipz 10y agoI have a question about null being able to subvert types, using Java an example, if I write foo.upperCase() and foo is a string, the type check succeeds but will produce an NPE at runtime. Why doesn't javac catch that foo is not set i.e is "null." Why is null above type checks?
- zaphar 10y agoBecause whether foo's value is null is for most cases only detectable at runtime precisely because java doesn't have the capability to express disjoint type sets in it's type system the way that say Haskell or F# do. This inability means that the programmer can't tell the compiler what code paths produce null vs what code paths produce string. As a result the compiler has to assume that all codepaths could produce both. There are some trivial cases where the compiler could figure it out for you but most of those cases are not very useful in practice.
- bogomipz 10y agoInteresting, is there a formal name for this kind of type system that has the ability to look at the code paths and express disjoint type sets? Is this a trend in newer languages in general or an FP specific thing?
- airless_bar 10y ago> formal name non-shitty > a trend in newer languages yes, only discovered a few decades ago :-D
- bogomipz 10y agoI understand making a snarky comment in addition to some meaningful commentary but really two useless comments? Why even take the time to do so?
- airless_bar 10y ago