25 ms·
Intent to stop using 'null' in my JS code
- austincheney 6y agoThis is problematic in that you don't control external APIs. For example look at the DOM which preferences null but returns undefined when there is a language construct in the way: document.getElementById("asdf") // returns null; document.getElementsByTagName("asdf") // returns []; document.getEleemntsByTagName("asdf")[0] // returns undefined document.getElementsByTagName("body")[0].getAttribute("asdf") // returns null // document.getElementsByTagName("input") // assuming not empty for the next several lines document.getElementsByTagName("input")[0] // Element object document.getEleemntsByTagName("input")[0].value // returns "" as valus is implicitly an empty string if not supplied document.getElementsByTagName("div")[0].value // returns undefined even though the element is present but expresses an inference to an unsupported property I completely agree supporting both null and undefined complicates some forms of validation, but I have accounted for this in my test automation. I don't encounter this problem with input validation or managing event handlers. Here are the rules I use: * undefined is a value where a value is never before assigned. Yes, you can do stupid things in opposition to the default such as arbitrarily assigning undefined or even redefining undefined to an assignment, but those footguns are not be accident. * null is a value that is explicitly assigned. If you program with those assumptions in mind you are safe 99% of the time given default language constructs, which doesn't account for the intentionally bad decisions other people make. This also helps with troubleshooting because when an error is encountered due to a null or undefined value the assignment distinction helps to diagnose the problem.
- roguesherlock 6y agoI actually find all of the return values reasonable. As you said, undefined == I just don’t know what the value is null == I know that there isn’t supposed to be a value here.
- amw-zero 6y agoWhy is this distinction important practically?
- jolux 6y agoIt shouldn’t be but due to the way JavaScript is structured it is.
- lmm 6y agoBecause they mean very different things. E.g. "no-one owns this land" is very different from "I don't know who owns this land". "You don't need to do anything" is very different from "I don't know what you need to do". "No-one's in that room" is very different from "I don't know who's in that room". Of course the practical difference depends on context, but so does the practical difference between 2 and 3.
- amw-zero 6y agoThat’s not what I asked. I know what the distinction is. I asked why would I ever need that distinction in a program. In 10 years I’ve never come across a situation where I found that distinction useful.
- thenanyu 6y agoAgree. I would never attempt to write flow control that had different cases for handling undefined and null. It feels so extremely brittle
- reificator 6y agoUndefined should mean in most cases that you've made a programming mistake, be that a typo or an invalid assumption about the type of thing you're getting back. Null should mean in most cases that the data you wanted to access was invalid, but you can expect it to exist there in other circumstances. Neither are a guarantee in JS, and you can find counterexamples for the counterexamples of the counterexamples, but that's the intention behind each.
- anuila 6y agoIf the value is expected to be a Boolean, use undefined to set it as undefined. For everything else, use false to “explicitly assign it”, you don’t need a third type.
- JimDabell 6y ago> use false to “explicitly assign it” Then you still have null, you’re just spelling it funny while confusing all the other developers who have to deal with your code and making it incompatible with language constructs like the nullish coalescing operator. If the concept you are trying to express is “null”, then please use null to represent that instead of bringing in a poor substitute like an overloaded false.
- anuila 6y agoNo, most likely I'll just use undefined because my abstractions are not a complicated mess that need 2 null types. Found? string Not found? undefined
- JimDabell 6y ago> most likely I'll just use undefined You were telling people to use false and that’s what I was responding to. That’s why I quoted that part in my comment.
- seanwilson 6y ago> document.getElementById("asdf") > document.getElementsByTagName For what it's worth I usually wrap these functions to e.g. throw an error if they don't find any items as that's what you usually want to happen but forget to write checks for. It's rare I'll use getElementById and expect it not to find something. Lots of undefined + null values crop up from situations like this where you want to fail when something you expect to be there isn't found e.g. file handling, dictionaries, web requests. It's a no-brainer to use TypeScript as well if you want robustness from these kinds of bugs, where returning undefined or a value is more practical because TypeScript will force you to check for undefined. I don't understand why anyone would willingly give up to type checks like these as it's obvious to me you can't compete with automated checking.
- anonytrary 6y agoconst w = (fn, _) => function(...args){ return (_ = fn(...args)) === null ? undefined : _; }; document.getElementById = w(document.getElementById.bind(document));
- cmroanirgo 6y agoI seriously hope this is joke code. Returning undefined for null, as well as changing dom functions is a great way to ensure unintended side effects will creep into your code.
- philihp 6y agoFor sure you wouldn’t actually commit this, but it’s for sure interesting to do the mental gymnastics to understand it.
- anonytrary 6y agoIt is an illustration of a concept. I wouldn't call it a joke, but I also wouldn't use it.
- sergeykish 6y agoundefined would be rare foo //Uncaught ReferenceError: foo is not defined if not property access, and it lies o = { foo: undefined } o.foo //undefined o.hasOwnProperty('foo') //true Array is an object, access by index is property access a = [] a[0] //undefined That's unfortunate. In Ruby: foo #NameError (undefined local variable or method `foo' for main:Object) defined?(foo) #=> nil o = Object.new o.foo #NoMethodError (undefined method `foo' for #<Object:0x000055f2f4e56e78>) a = [] a[0] #=> nil And Ruby enforces method arity and keyword parameters: def foo(value) end foo #ArgumentError (wrong number of arguments (given 0, expected 1)) def bar(value:) end bar #ArgumentError (missing keyword: :value) Basically it throws on undefined. I think reimplementation is a great way to uncover how things work, Ruby "fix" for property access http://sergeykish.com/ruby-like-javascript-undefined.rb http://sergeykish.com/ruby-like-javascript-undefined.rb Anyone knows how to relax arity?
- deleted 6y ago[deleted]
- joeblow21 6y agoPro tip: Start by improving your English. Then work on javascript.
- Waterluvian 6y agoI use null in data because Json. But otherwise I just leave undefined to play the role of "this optional argument wasn't defined" and null for everything else. I like null because You have to specifically set something as null. I can run into undefined through typos and such. I dont think you can accidentally hit null. P.s. This reminds me of the one time in Python I thought, "Damn I wish I had both undefined and None". I needed to know if a user was omitting an optional argument or passing an explicit None into it. Ie. This data is optional and the data might be "None". I ended up using kwargs which weakened my function as it nolonger described all the possible arguments.
- anuila 6y agoUndefined is “stored” the same way in JSON, which means it isn’t. This only becomes a “problem” when you convert a JSON string to an object and the data contains an array with a null value in it. That’s the only case where null exists in JSON, and I think it’s generally pretty rare.
- Waterluvian 6y agoNot sure I follow. JSON has null. It doesn't have undefined.
- toast0 6y agoYou said > But otherwise I just leave undefined to play the role of "this optional argument wasn't defined" And the reply is saying that's how JSON uses it too. Anything set to undefined will not be serialized, as if it were optional and not defined.
- Waterluvian 6y agoArguments belong to functions. Sorry I was wandering all over.
- Izkata 6y ago> Undefined is “stored” the same way in JSON, which means it isn’t. Null is: >> JSON.stringify({"foo": undefined}); "{}" >> JSON.stringify({"foo": null}); "{\"foo\":null}"
- hn_throwaway_99 6y agoWhile I agree the presence of both null and undefined in JavaScript can make things a big pain in the ass, trying to get rid of null in favor of undefined is a huge mistake. For example, a couple years ago GraphQL specifically added support for the difference between undefined and null, and it was a good change. An optional field on an input type can be left off (in which case it is undefined) or it can be explicitly set to null. For a mutation, these have very different meanings: undefined means "don't update the property" while null means "update the property to null (which usually means 'delete')". These are very different things. This thread, https://github.com/graphql/graphql-js/issues/133 https://github.com/graphql/graphql-js/issues/133, is a good overview.
- foolmeonce 6y ago> null means "update the property to null (which usually means 'delete')". That is pretty humorous, null means make it undefined, so I guess false will need to mean make it null, and true can mean make it false? The general problem is trying to get enough metadata directly into the language to manipulate it's own programs with such metadata. Of course this never works it just goes to an edge case so absurd that absurd syntax stays reserved for things with meta operations so they can work on most things yet not themselves or each other.
- hn_throwaway_99 6y agoI don't think this is an absurd edge case at all, and your initial paragraph doesn't make sense to me. Let's say I have an object that represents an object in the DB, and one of the properties on that object represents an relationship to another entity which may not always be there. Then setting null on the object would mean set the corresponding DB column to null. How is that a discrepancy? The problem with JS isn't that it doesn't really need null, it's that it doesn't really need undefined, but now that undefined is there it's impossible to rip it out. Most other languages that have null also have a separate concept of "doesn't exist": accessing a non-existent property would throw an exception, not return null, and for example you could tell the difference between whether a Map has a value at all vs has a null value by calling the equivalent of map.containsKey. Point is it is often necessary to tell the difference between "object doesn't have a property" vs. "property is null", and for better or worse (I think mostly worse) JS uses undefined to distinguish between those cases.
- ibraheemdev 6y agoWhat about external libraries? While it might be a good idea to stop using null in your own code, you should probably still make it a habit to check for both null and undefined to avoid problems with external code. > we cannot remove null from JavaScript, but we can pretend it doesn't exist Even if it does become general convention to not use null, as a developer, you cannot depend on that convention and skip null checks in favor of undefined, because null is deeply engrained into the language itself. So... we can't really pretend that it doesn't exist
- slewis 6y agoAs others have mentioned, you can’t get rid of null, because of third-party libraries for one. Instead your code should treat them the same at comparison time: ‘== null’ is the canonical way to check for either.
- eyelidlessness 6y agoThe language is uniquely poorly defined for this. Node got this almost right, by baking in a sort of Option type to callback signatures. The community ignored it and ignored failure conditions. It’s bonkers that there’s at least three (yes three, not two; empty array slots are neither null nor undefined, they just resolve to undefined if you access them like any missing property on an object) nullish types in the language but you can’t gloss over that by pretending they don’t exist.
- brundolf 6y agoMy personal approach is to pretend the distinction doesn't exist by writing my code as if it doesn't exist. Mostly this means using "foo == null", which works for both. Using undefined as a default convention is well and good, but trying to get to a place where you can guarantee it across a whole project is folly. I've personally seen the JSON case, in particular, result in some fairly pointless extra complexity converting all nulls to undefineds.
- vikingcaffiene 6y agoThe author makes compelling arguments but I respectfully disagree with their conclusion. Null exists for cases where you want to set the the absence of a value intentionally. It is literally the value of having no value. Undefined exists for cases where no value has yet been set. It's a subtle but important difference and allows a certain amount of nuance and expressiveness in ones code to communicate intent. I do think it's fair to say that a lot of devs don't use them that way. They _are_ for separate use cases though.
- Aeolun 6y ago> Null exists for cases where you want to set the the absence of a value intentionally. Only in Javascript though. In Typescript this would be clear from the fact that the type has the property. Of course Typescript is not Javascript, but nobody should use plain JS anymore.
- ZephyrBlu 6y agoWhat if you want your property to have a default value, such as null?
- chousuke 6y agonull is not a very good default value in most cases though, since the operations you do with values of "real" types will not work on null. Therefore actually using your "default" value is pretty much guaranteed to be a bug, identical to using an uninitialized variable. It would be better to just error out and not allow the uninitialized usage at all, but unfortunately that's not possible in Javascript.
- ZephyrBlu 6y agoThat's the point though. I can easily do a null check to handle whether or not to process/use the value. For instance, if I'm fetching some data I usually want to initialize the data variable as null for a couple of reasons. 1) null is not truthy, empty arrays and objects are 2) It shows that the variable is supposed to be filled, unlike undefined
- resonious 6y agoI agree with many folks here on HN in that `null` and `undefined` have important differences. `undefined` appears when you access an invalid field, while `null` appears when you access a _valid_, but empty field. This information comes in handy during debugging. If your code is trying to access a field on `undefined`, then you may well have a typo. If your code is trying to access a field on `null`, then you've simply made some wrong assumptions about your inputs. The next steps for those two scenarios are quite different! Arguing that all `null`s should be replaced with `undefined`s in JS code also kind of implies to me that JSON should replace the `null` keyword with `undefined`, which just sounds crazy to me. Why store "undefined" values in serialized data? If it's not defined, don't define it... `null` allows you to convey that "this value may exist, but currently doesn't".
- dheera 6y agoAgreed, however we look at it there is no way to change the several dozen JSON libraries out there. People should avoid using undefined, not avoid using null.
- ZephyrBlu 6y agoAvoiding undefined is more preferable to me, since then it only shows when when you screw up.
- anuila 6y agoHow can you avoid using undefined if it's the default value for `prop.nonexistent` and `return`? Have you ever used JavaScript?
- afiori 6y agoone can argue that if you obtain a value in such a way you should validate it first or not use it at all
- rbanffy 6y agoFurthermore, if the function returns `undefined`, as in "it's not expected to return a value", you should probably not try to assign its return value to anything you'll see again.
- jez 6y agoThis issue was opened on April 1, 2019. Was that a coincidence?
- breck 6y agoI’ve been trying a new thing lately: never ever use null or undefined or NaN in my own code (external libs you have to account for), instead defining my own invalid types. So ‘class undefinedDivideByZero extends InvalidType’. Then just check if a value is an instance of InvalidType. Then you can create much more specific invalid types. If you have to account for 3 anyway, might as well account for N, and then create more information rich types. Is there a name for this pattern?
- pwdisswordfish0 6y agoYes. You just reinvented exceptions.
- breck 6y agoExceptions are about control flow. Nulls and undefined are about types. The flow generally continues on with the latter. So I’m wondering what the term is for when you have a whole slew of invalid types but continue on without any exception handling and instead handle it via type systems.
- fendy3002 6y agoIn java / C#, this is how their exception works. Indeed it is bad in performance, but you can define exception as flow. For example: try{ } catch(SQLException ex) { } catch(MathException ex) { } So it is kinda correct thay you reinvented the exception handling in java / c#, without really raising error / exception itself.
- breck 6y agoThanks that's a clear example. What I'm looking for is a name for a pattern where a function returns (typeof ExpectedType | typeof InvalidType). Say it's a pipelined compiler and you want all the passes to continue even with InvalidTypes, and then at the end of the pipeline the result is a structure of the correct shape, but there may be some "holes" filled with InvalidTypes. So one way to say it is exception types without the Try/Catch.
- steve_adams_86 6y agoI had this discussion recently in a pull request - the reviewer wanted to know why I was using both null and undefined. Like several people have mentioned, it’s useful in JavaScript in particular to indicate known unknowns as null and unknown unknowns as undefined. Since it was a good question though I actually spent quite a bit of time and energy analyzing this and trying to figure out if my choice still made sense to me. It’s somewhat reassuring to see these comments here because at the time, I couldn’t deny that my solution isn’t ideal. At the same time, I know that favouring a less explicit approach to describing empty values is inevitably even more confusing - there has to be some way to indicate why something is empty. It’s still hard to program with a solution you know isn’t ideal... I really wanted a better answer or to find a better way forward with the reviewer, but in JS land it seems like an unfortunate but viable way to work.
- tylorr 6y agoI feel that the distinction between null and undefined is less significant when you have types such as in TypeScript. The types let you know if a property can be optionally provided and there are constructs that help with that such as the ? operator.
- andyp-kw 6y agoI try really hard to not complain, because we're stuck with JavaScript. But I'd just love to tear it down and start again. For something that's supposed to be a universal programming language, it's got so much stuff like this that makes it so unfriendly to newbies.
- danielheath 6y agoIf you don’t need ie11, wasm works everywhere. Emscripten can produce js as well as wasm, so you can build both and deliver according to support.
- elevenoh 6y ago>it's got so much stuff like this that makes it so unfriendly to newbies what's another one?
- andyp-kw 6y agoI work with many developers who don't speak English as a first language and they find things in JavaScript like .filter to be hard to grasp, but .Where in C# makes perfect sense to them because they understand that they're looking for something in a list "Where" their conditions are met. That's just one example of things in JavaScript that are poorly named for people to guess what they do.
- naniwaduni 6y agoThe opposite, actually. "filter" is just a verb you can look up in a dictionary and roughly understand its meaning. "Where" is grammatical and hard to grasp without a holistic understanding of English grammar. Linguistic Moravec paradox, if you will. Now, explaining Ruby's collect/detect/inject/select/reject, that's a whole different matter...
- andyp-kw 6y agoI don't care what it says in the dictionary, I'm going on real life cases from my colleagues in SEA who don't speak English as a first language.
- benatkin 6y agoDefault parameters are huge. I'm glad to see this post and hope libraries will adapt. I think pragmatism outweighs the semantic distinction and json serialization concerns. https://github.com/prisma/prisma-client-js/issues/572 https://github.com/prisma/prisma-client-js/issues/572
- crooked-v 6y agoThis kind of thing makes me wish that some variety of Optional/Either/Maybe was a de facto standard in JS, like early promise work turned out.
- mchaver 6y agoReScript (formerly BuckleScript/ReasonML) is a nice option, but I agree in an ideal world these features would exist in the JS standard.
- yakshaving_jgt 6y agoCould there be a data structure that allows us to model possibly missing values? Maybe.
- mirekrusin 6y agoThere are: 1. falsy values 0, -0, 0n, '', null, undefined, NaN 2. null 3. undefined 4. absence of property and property set to undefined You have to know differences between those when coding in js/ts/flow. Ie. no 4. has implications when iterating ie. Object.keys({ foo: undefined }).length === 1. Education around those - yes, but blacklisting null? Sounds a bit silly, however I agree that most developers overuse null when they actually mean undefined. One example in code where null vs undefined can be used is sql.update(table, where, { foo: null, bar: 1 }) - meaning update foo to null vs sql.update(table, where, { foo: undefined, bar: 1 }) - where undefined means, don't do anything with that column. This helps a lot because it's much more verbose to conditionally construct object with a property or without it, however it's easy to set it defined/undefined.
- deleted 6y ago[deleted]
- soheilpro 6y agoI've been doing the same for some time. If you use TypeScript and TSLint, there's also a rule for that: https://palantir.github.io/tslint/rules/no-null-keyword https://palantir.github.io/tslint/rules/no-null-keyword
- nathias 6y agonull is negation, undefined is privation, the first is the intent of absence the other the absence of intent
- fendy3002 6y agoCMIIW, undefined only exists on dynamic typed language. You can't access undefined property in static typed, unless using reflection. So if anything, you should not set something as undefined, but you can update something as null.
- megous 6y agoWhat's so hard for checking for null or undefined? All you need to do is use a condition like `v == null` or `v == undefined`. I like the first one more because it's shorter, but both are equivalent to `v === null || v === undefined` And you can ignore the distinction then.
- mypalmike 6y agoUndefined in js occurs where other languages either throw exceptions or fail compilation. In other words, it represents invalid program state. A language with this "feature" may as well do other insane things, like treat a call to a nonexistent function in some quirky way, like recursively calling the current function. Gotta keep that program running! And if js did that, there would be web devs here on hn arguing that it's a good thing, explaining how to incorporate the feature into designs. *Edit - recursive rather than no-op, to make it do something that people might abuse.
- venfen 6y agoIn my job I do a lot of code reviews and I notice that by using Typescript, devs tend to write worse JavaScript code. I often see that developers are assigning `undefined` to properties in order to clean value or to satisfy badly written TS interface, instead of just using JS `delete` statement. Also a lot of times I see passing `undefined` to methods with optional params, instead of just skipping them. Here some bad practices: If there is an interface: `interface ISomething { x?: string };` and obj of this interface to have `obj.x = undefined` instead of `delete obj.x`. Writing methods: `function x(param0, param1?, param2?) {}` to be used as `x(1, undefined, '2');` instead of creating the func as `function x(param0, option: { param1?, param2? })` and using as `x(1, { param2: '2' })`. Returning undefined from a function: `function x(): undefined { return undefined; }`, instead of `function x(): void { return; }`. Mixing the meanings of `undefined` and `null`, can bring a lot of troubles for JS devs when they use `Object.keys` or using `arguments` in function. IMHO If we keep that `undefined` means missing while `null` means no value, then we will have better JS code, using: `'x' in obj` instead of `obj.x === undefined` or `typeof obj.x === 'undefined'`, `delete obj.x` instead of `obj.x = undefined`, `obj.x = null` and then `obj.x === null` instead of `obj.x == null`.
- Chyzwar 6y agoYou should probably never use delete. Not only it mutates objects but also have perf penalty. > If there is an interface: `interface ISomething { x?: string };` and obj of this interface to have `obj.x = undefined` instead of `delete obj.x`. In typescript additional properties are not a problem. Since it is using structural typing. In most cases spread and restructuring are better options for merging/overwriting and deleting. It is safer and easier to reason about. > Writing methods: `function x(param0, param1?, param2?) {}` to be used as `x(1, undefined, '2');` instead of creating the func as `function x(param0, option: { param1?, param2? })` and using as `x(1, { param2: '2' })`. I am not fan of creating functions taking options objects as argument. In many cases is better to create specialized functions
- coding123 6y agoIt's kind of awesome that JS has both null and undefined. A lot of languages sometimes wish they had a descriptor for null to indicate if it mean we have the value but it's blank vs we don't have the value. Now, that being said - a JS object can certainly HAVE a value that is undefined - so that's always fun.
- sethc2 6y agoI like the semantic differences between null and undefined. I’d rather spend the time cleaning up the codebase to use them appropriately. Maybe you should use typescript and be forced to think about the interfaces of your various functions; their types and how you expect a consumer to use them.
- gitowiec 6y agoI learnt a lot just reading the thread. I wish the strong mode came to life.