DEV Community

Cover image for You don't need null

You don't need null

Lou Cyx on January 02, 2022

Discussion was locked because I moved away from DEV to blog on my personal website. If you want to chat about the content of any article, hit me u...
The discussion has been locked. New comments can't be added.
Collapse
 
martinpham profile image
Martin Pham • Edited

1) Json doesn’t have undefined, also when you interact with other sources (db, cache,..)
2) null and undefined are totally different things, used in different cases.
When the value is null, you know it was defined
When the value is undefined, you know it wasn’t defined

Example, a validator should know if a variable is missing (undefined), or it’s presented without value (null)

Collapse
 
romeerez profile image
Roman K

Wondering how no one still mentioned 'in' operator:

const a = {}
const b = { key: undefined }

console.log('key' in a) // false
console.log('key' in b) // true
Enter fullscreen mode Exit fullscreen mode
Collapse
 
loucyx profile image
Lou Cyx • Edited

Several reasons, I guess:

  1. That would make the argument saying "there is no way of differentiate between intentionally set and unintentionally set" for undefined invalid, because with in you can figure out if it was intentionally set as undefined, or is actually missing from the object.
  2. Because if you set it to null, in will return true as well, so that doesn't make it better than undefined, nor different. So another argument in favor of "they are the same".
  3. Because there are other ways to check if something exists than in.

TL;DR: Because is an argument in favor of the article, I guess I could even update it with that :D

 
martinpham profile image
Martin Pham
  1. So you’re saying, with the “in”, when you intentionally set the value to “undefined”, it means the value is “defined”?
 
loucyx profile image
Lou Cyx

You should explain that to me. I mean you're the ones saying "null means something is defined but intentionally empty", so you're the ones saying there's a need for that kind of thing ... I'm just saying that using in you can achieve the same thing with undefined ... in both cases we are saying something is "defined but not quite", just with different wording ... and I still don't get why you need that distinction 🤣

 
romeerez profile image
Roman K

and I still don't get why you need that distinction

Well, I tried to find an example but cannot :)

And in this whole long holywar I cannot see a single example why null is better. JSON is one example, but let's imagine we delete all null keys from objects after getting data. Okay now we have libraries which are requiring null, and we have to convert undefined to null when using them. And that's all.

Maybe null make life easier when you are not using TypeScript, I don't know. With TypeScript you can see type in the code, and without it people are probably doing console.log(data) all the time to see data shape, and if values are omitted this is confusing.

Good article, thanks for writing, please keep doing it!

 
martinpham profile image
Martin Pham

Well not only me, also other people here were trying to explain to you, but seems you just didn’t want to get it.

In my experience, consistency is one of the most important thing. Example: my service exchanges data with other services, they will have the same schema where they agree how an object looks like.
When other service sends me a kebab request with “ketchup” is null, I understand this kebab should be made without ketchup.
If the “ketchup” key is undefined, I understand that this kebab is on hold, because its definition is incomplete.
But if the “ketchup” key is missing? Wtf? Maybe the request was broken in the middle? Maybe the other service updated new schema and changed the key? Maybe the “ketchup” key is deprecated?
And it turned out it was omitted because some guy thought it’s cool to save some characters…

I understand that’s there is always a way to handle it. But ask yourself: Would you like to write inconsistent code with confidence, or you’d prefer monkey patches here and there with thousands of conditions?

Happy Befana btw

 
loucyx profile image
Lou Cyx • Edited

Maybe null make life easier when you are not using TypeScript ...

You can use TS without using TS, by typing with JSDocs. Try this out in VSCode:

// @ts-check

/**
 * @typedef User
 * @property {string} id - The user's unique ID.
 * @property {string} name - The user's name.
 * @property {string} [email] - The user's email address (optional).
 */

/**
 * Get a user by ID.
 * @param {string} id 
 * @returns {User}
 */
// Red squiggly here, because we are missing `name`:
// But if you miss `email` is ok because that one is "optional"
const getUser = id => ({ id });
Enter fullscreen mode Exit fullscreen mode

Thanks a lot for that last line, Roman. I greatly appreciate some good vibes in this comment section ❤️

 
loucyx profile image
Lou Cyx

In my experience, consistency is one of the most important thing

If you really think about it, we can have that same consistency with undefined instead of null. At work we have contracts between the API and the client. We translate the type definitions from the back-end in .d.ts files we can use from TypeScript and JavaScript. When something is optional in the back-end, the type is Type?, not Type | null or Type | null | undefined, so we know with confidence that we can send a value or undefined (namely, not send it). Same applies for the things we get of the back-end, if something we fetch could be missing, then the type is Type? again, which means it can be undefined, and we deal with that either with default values, optional chaining and all that sweet tech we have to deal with nullish values.

Long story short, you have a convention to use null and undefined, that convention could use only undefined as well and work ... and this still doesn't negate the fact that you can use undefined everywhere, except when you talk with the back-end.

I updated the article adding some other folks that have a similar opinion to mine (even a feature request in consideration to update Angular so it only uses undefined).

 
romeerez profile image
Roman K • Edited

Offtopic, I was reading your previous article and wondered why to compose functions in this way update('user')({ ...data })(user), looks like you are intentionally keeping all functions with one argument, and I don't understand why not to have a function with 3 arguments instead. I'd love to read a new article from you "You don't need second argument" explaining this pattern. Looks crazy tbh.

Also "You might not need" is a way better naming, because people need classes in Angular, indeed they need mutation in Vue, null in response from database.

 
loucyx profile image
Lou Cyx • Edited

Is a pattern called currying, it allows you to create functions from functions and make everything more reusable:

const update = property => value => object => ({
    ...object,
    [property]: value,
});

const updateName = update("name");
const blankName = updateName("");
const nameFoo = updateName("foo");

const blanks = [
    { id: 1, name: "Luke" },
    { id: 2, name: "Roman" },
].map(blankUser); // Returns the array with `name` on both set to ""

blanks.map(nameFoo); // Returns the array with `name` on both set to "foo"
Enter fullscreen mode Exit fullscreen mode

Maybe is not the best example, but basically you can create updateX and reuse it all you want, with different values for different objects ... compared to doing the same with 3 arguments:

const update = (object, property, value) => ({
    ...object,
    [property]: value,
});

const blanks = [
    { id: 1, name: "Luke" },
    { id: 2, name: "Roman" },
].map(object => update(object, "name", ""));

blanks.map(object => update(object, "name", "foo"));
Enter fullscreen mode Exit fullscreen mode

We need to write update and pass every argument with every use. Currying is one of those things that when it "clicks", you never go back. A popular library that uses this a lot is Rambda.

Also "You might not need" is a way better naming, because people need classes in Angular, indeed they need mutation in Vue, null in response from database.

I considered that rename a few times, but my point is that you don't need it in your own creations, that's the main reason I have my articles set so that is more for "almost experts" than "beginner". Beginners using other folks tools need to learn all this stuff, way later we learn about the things we don't need to code, but might need to interact with somebody else's code.

Screenshot of a experience level set to 7 of 10

 
romeerez profile image
Roman K • Edited

Thanks, but still more in depth article would be awesome. By your example I can see that in plain JS carrying is worst thing to happen: if you see somewhere in the code nameFoo, you'll probably assume it's a simple string, while actually it's a function which takes object and returns new object with updated name property. With TypeScript it's still very confusing, okay we can hover and see the type, but I assume it will show a complex barely readable type. And I hardly imagining how it is even possible to write all this types, how much complex generics will be needed for this, how much unions.

In TS function "update" has to take a union of all table names. And what if for one table update should have different implementation?

While in true FP languages there is a function overloading and you can define them separately for different tables, which is removing all downsides and sounds awesome. But JS/TS is not such language so it's a good question if the same approaches really worth to be used here? (I didn't ever worked with FP language)

I assume you are following this carrying approach on real projects and you know how to deal with difficulties on this way, so let me repeat myself, isn't it bright idea for article? There are a lot of articles on the topic ofc, but they only sharing basics and explaining nothing useful about how to deal with it in real world, when to use and when to avoid. Not insisting of course, maybe there are such articles and need to search harder and play with it myself

 
loucyx profile image
Lou Cyx • Edited

Sure thing! I'll create an article about currying and mention you on it for pushing the idea if you don't mind ^_^ ... about the TS implementation, that update function could look something like this:

const update =
    // Generic for the property name
    <Property extends PropertyKey>(property: Property) =>
    // Generic for the value
    <Value>(value: Value) =>
    // We expect the "Source" object to be an object of unknown properties
    <Source extends Record<PropertyKey, unknown>>(
        object: Source,
    // We return that Source combined with the new property and value
    ): Source & { [property in Property]: Value } => ({
        ...object,
        [property]: value,
    });
Enter fullscreen mode Exit fullscreen mode

I do love to do TS + FP, so creating an article about this might be interesting for other folks as well 😄

 
romeerez profile image
Roman K

Awesome! No one yet wrote article in my honor, I'm flattered :)

I wish it could explain "Why" and "When to use" no less than "How to use", so pros and cons.

So far carrying looks like a lego and there is something in it, definitely there is something about it.

Collapse
 
martinpham profile image
Martin Pham

You don’t need “in” /s

 
loucyx profile image
Lou Cyx

lol

Collapse
 
martinpham profile image
Martin Pham

Btw it’s fun when

  • Access a variable which is not defined: we have ReferenceError
  • Access an attribute which is not defined: no error, it returns undefined
 
loucyx profile image
Lou Cyx • Edited

Yup, it kinda sucks, but is preferable to return undefined for something that isn't defined ... you can still check if a variable exists before trying to access it, by using typeof:

console.log(foo); // ReferenceError
console.log(typeof foo !== "undefined" ? foo : "Nope"); // "Nope" 🎉
Enter fullscreen mode Exit fullscreen mode

Accessing properties is a better DX, and with ?. and ?? is even better:

const obj = {};
console.log(obj?.foo ?? "Nope"); // "Nope" 🎉
Enter fullscreen mode Exit fullscreen mode
 
martinpham profile image
Martin Pham

I’m not talking about the check. I’m just trying to point the inconsistency between two cases about the same thing.

 
loucyx profile image
Lou Cyx

But that's the thing, they aren't the same thing. One is trying to access something not declared in the scope, while the other is trying to access a property of something that is declared in the scope. You can test both with typeof === "undefined", but if you try to access something undeclared you get an error, which sucks, but that's how it works. Nowadays is very difficult to end up in this scenario tho, because editors will let you know if you're trying to access an undeclared value.

Collapse
 
patroza profile image
Patrick Roza • Edited

Json can model undefined through absence of a key. Otherwise fully agree.

When reading a model, I would generally consider absent or undefined values an error, or eg a just in time migration that needs to still happen :)

Otherwise the contract is too fuzzy for my taste

Collapse
 
martinpham profile image
Martin Pham

That’s the thing.
Eg from a json response, a “post” which has “deleted_at” is null means it’s not deleted. But if the “deleted_at” is missing, it should be considered as invalid api response

 
loucyx profile image
Lou Cyx

That depends on the API implementation. This is like saying:

You need to use null because I wrote if (value === null)

Which is kinda like a Straw Man. If the API has a poor implementation that requires null, that doesn't mean you need to use null in your entire codebase, that just means you need to use it in your surface of contact with said API.

 
martinpham profile image
Martin Pham

Sorry but I wouldn’t consider an api which has consistent response for nullable object, as a poor implemented api..

 
loucyx profile image
Lou Cyx

Me neither, that doesn't have anything to do with null. You can just omit something when is "nullish" which translates to .... you guest it, undefined, and it has the added value that payloads are smaller 🎉

 
patroza profile image
Patrick Roza

Absence and null are different things, as said.
What constraints are you under that these minor payload sizes matter? you’ll probably get more out of gzip than omitting nullish.

 
martinpham profile image
Martin Pham

Payloads are smaller by omitting some characters, good.
But if it causes confusion between null (value is set as no value) and undefined (value is not set), I wouldn’t take it as a good thing.

 
loucyx profile image
Lou Cyx

"Absence and null are different things" ... how? The size of the payload doesn't only affect the request, also the parsing. You're literally loading something trough the wire and in memory that you could omit, just to use null X_X

Collapse
 
loucyx profile image
Lou Cyx • Edited

With tech like TS, contracts are actually pretty easy to define. There are tools out there that turn all kind of type definitions in .d.ts files, that you can use from TS or JS with editors such as VSCode to get the type checking. If an API defines something as optional, in TS that's Type | undefined, so you can omit that key or send that Type and it will work :D ... if the types change in any way, you should update your type definitions accordingly (using the same tools), and you'll get errors directly in your editor 🎉

Collapse
 
loucyx profile image
Lou Cyx
  1. Yes it does, when you skip a value, tada! That's undefined 😉
  2. Because JS folks decided to do so. Other languages that only have a single nullish value use that for any scenario that requires nullish values. From JS we can also just use one, and what I say in this article is that you can just use undefined.
Collapse
 
martinpham profile image
Martin Pham
  1. As I replied to other guy. The response should be consistent, if you skip this value, tada! an error should be thrown. Because you won’t know if the value is missing (eg: it has, but api fails to give it) or the value is not defined.
  2. Other languages which don’t have it because they are more strict, where it’s bad when you try to use an undefined variable. JS was born as a mess, but growing up as a flexible language, that’s why we have undefined and null to use together
 
loucyx profile image
Lou Cyx
  1. If the API fails, you should handle that in other ways (response headers and proper error handling), if the API responded with the wrong body, that will be a problem either if you use null or undefined, so I still don't see much value for null in this scenario. If a value can either come or not, then you can define it as optional (meaning Type | undefined), and in the front end you can just do value ?? "default value" or if (value === undefined) { throw // ... } or whatever 😄
  2. You should take a look at optional chaining and nullish coalescing, saying "it's bad when you try to use an undefined variable" feels like you might not be aware of this operators, but long story short, it's no longer bad. You can even "call" undefined 🎉
 
martinpham profile image
Martin Pham
  1. Of course you can handle it anyway, but how you know if the value is missing (an error), or if the value is not set?
  2. I was saying that about other languages, not js
Collapse
 
omgimalexis profile image
Alexis Tyler

“Why would you ever need to make that distinction? Both are "nullish", and you don't need to differentiate between "intentionally missing" and "unintentionally missing".”

This is quite often needed? How do I know if a user set this as “undefined” or if it was not set by the user. Hence the need for null.

Collapse
 
loucyx profile image
Lou Cyx • Edited

When a value is "optional", that only means it can be defined or not, it can be a type or be nullish (the Maybe type I mentioned). So something that's optional has the shape Type | undefined, or Type?

So if a value for a user is let's say a string name that might be intentionally left blank or not, then the type for it is string | undefined or string?. So if the user set it to be empty intentionally, then you can set the value to "", and if not then set it to undefined.

You can then send it like this if the user left it blank intentionally to the back-end:

{ "userId": 1, "name": "" }
Enter fullscreen mode Exit fullscreen mode

And if the user didn't set it at all, then:

{ "userId": 1 }
Enter fullscreen mode Exit fullscreen mode

Trust me, every piece of code written using null in JavaScript/TypeScript, can be written without null, and it generally ends up being cleaner.

Collapse
 
martinpham profile image
Martin Pham

Sorry but when a value is optional, it doesn’t mean it can be null.
Eg a “pizza” with optional “extra_topping”. If you don’t want to have extra topping, it should be null.
But if it doesn’t have “extra_topping” (value is undefined or absented), the object should be considered invalid.

 
loucyx profile image
Lou Cyx

Why?! If it doesn't have extra_topping then it doesn't have any, and if it has that property then it has extra toppings ... the one defining that "rule" that if something is missing then is invalid is you.

 
martinpham profile image
Martin Pham

If you call a pizzeria to order a pizza, you don’t mention extra toppings. What should they think?
1) You don’t want
2) You forgot to mention

 
loucyx profile image
Lou Cyx

So much mentions of pizza are making me hungry 🤣 ... Answering:

  • If the pizza I ordered comes with some toppings and I didn't said anything, the pizzeria will send their default.
  • If I make clarifications about the toppings, then they'll update the pizza accordingly.

Do you say "keep the default toppings" every time you order?

 
martinpham profile image
Martin Pham • Edited

You didn't answer the question. The question is how would the pizzeria know if:
1) You don't want extra toppings
2) You want but you forgot to ask, or you didn't know that they offer extra toppings

1 should be null, because you stated it explicitly
2 should be undefined, because you haven't decided yet (yes, AKA you haven't defined it yet, that's why it's called undefined)

 
loucyx profile image
Lou Cyx

Did you ever actually bough a pizza? 🤣

  1. Because you didn't asked for any? You don't need to say "I don't want any extra toppings" every time you buy a pizza, you just need to clarify when you want them. Even in Doordash the extra toppings is an optional field, that you can just omit, you don't need to go into it and select "I don't want extra toppings", that's the "default".
  2. That's your problem as a client. You should know that there's an "extra toppings" option, and ask for it if you want them, or omit them if not. If I forget to buy a Pepsi to drink with my pizza and I was thirsty, is not a problem with the pizzeria, is my problem as a client.

Maybe this is not the best analogy for your point about needing 2 different nullish values?

 
martinpham profile image
Martin Pham • Edited

Alright, if you consider it's problem as a client, I have nothing else to say :)

// And you're right, I've never bough a pizza actually..

Collapse
 
omgimalexis profile image
Alexis Tyler

Gotta love how you completely skipped over the issue.

So how in the above do you suppose isSet would work since all you’re talking about is typescript types which don’t actually exist at runtime.

const settings = something.
if(isSet(something.option)){}

 
loucyx profile image
Lou Cyx

Using falsy values is like pointing a gun directly to your foot ...

const { option } = something;

console.log(
    `Option: ${
        option === "" ? "Intentionally unset" : option ?? "Not set yet"
    }`,
);
Enter fullscreen mode Exit fullscreen mode

And you'll get:

  • Option: Intentionally unset if the value is "".
  • Option: foo if the value is "foo".
  • Option: Not set yet if the value is undefined.

Really, you don't need null, or at least not for this.

 
omgimalexis profile image
Alexis Tyler

Yes... because everything is a string and everything is a single type. 🙃

All this post comes down to is “I don’t like null”. You don’t seem to have an understanding of the use so you make up reasons for it not needing to exist.

Don’t like it then don’t use it but it exists for a reason and the fact you can’t accept that shows what kind of developer you are.

 
loucyx profile image
Lou Cyx • Edited

It seems somebody skipped over the disclaimer at the bottom of the post! 🤣 ... should I assume that you can't live without two different nullish values, then? How do you think languages that only have one of them work? How do you think languages that don't have nullish at all work? If other languages can work without two different type of nullish values, why JavaScript can't?

Obviously there are different types, and different possibilities for optional values, that doesn't mean we then need to do all types Type | null and rely on falsy, that only means that if you have different types, you need to deal with them in different ways. Using null always is a really poor solution.

And if the number of downloads of the ESLint rule to avoid null tells us something, is that is not "only me".

 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

I've been using Lua for years and never felt the need to have a second non-value. You either have nil, or you have a value.

If you want a special value that's distinct from everything else, you just use an empty object and compare to it explicitly.

 
scottshipp profile image
scottshipp

If other languages can work without two different type of nullish values, why JavaScript can't?

That's an argument that doesn't hold up under further scrutiny, though. The "single nullish type" causes its own problems that JavaScript actually resolves.

Let's take Java as an example. It only has the single type null which is the default variable assignment for any object type. The "Map" interface in the Java standard library (Java's dictionary data structure) specifies that it returns null when client code gets a value from the map using a key that the map doesn't know about. Unfortunately, it's well-known that null is often also an actual value associated to keys in the map. This single flaw is one of the leading reasons why NullPointerException is the number one exception observed in the logs of production Java applications.

That situation is resolved in JavaScript, because the absence of the key is represented as undefined rather than null which disambiguates the cases.

 
loucyx profile image
Lou Cyx

You mean to say that all languages with only one nullish value, or no nullish value at all didn't figured out something that JavaScript did? In any other languages, if something is "optional" (meaning it can be a certain type or nullish), you just have to check before using it. If you don't, you run into issues (one of the main reasons some languages have the concept of Maybe instead of having nullish). In JavaScript you can still run into exceptions (TypeError) if you try to run something that's nullish or try to access a property inside a nullish. Both are solved using nullish coalescing and optional chaining, so you can still use either one of them. The solution to the problem isn't having two different nullish X_X

 
scottshipp profile image
scottshipp

You mean to say...

What I'm pointing out is that it's not a very good argument to say, "if other languages can work with a single null type, why can't JavaScript?" Just because other languages figure out ways to exist with only a single nullish type, doesn't mean anything in terms of the advantages of having more than one nullish type.

As a complete aside: you're actually making the argument for more than one nullish type yourself when you deflect to creating an optional or maybe type. There's also the "Null Object Pattern." These are all attempts to grapple with legitimate issues in programming. Using "null" and "undefined" together is just a different attempt.

At the end of the day, I could avoid the use of both null and undefined in my programs. That doesn't make it a good idea. I saw that someone made an HTTP server in pure BASH. Interesting? Sure. Does that mean I don't "need" HTTP servers? No.

 
loucyx profile image
Lou Cyx

But the argument about languages having only one nullish, or not having any, is to point out that generally "nullish" should be avoided, and with dealing with it we should be as straightforward as possible. Having 2 nullish is the contrary to avoiding nullish 😅

The article shows several scenarios in which you might need nullish, and how you can deal with it only using a single nullish value (undefined). Those same problems could be solved only using null and avoiding undefined, but you end up doing extra work when you could just use the nullish that the language uses.

At the end of the day, I could avoid the use of both null and undefined in my programs. That doesn't make it a good idea.

Why not? Is commonly known that nullish values are a bad idea (the creator of the null pointer itself regrets that decision). My point in the article is that if you have to use nullish, at least you can use the one that JS uses.

Is there an example in this article that's using undefined and makes you think: You need null for that?

 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

The whole "other languages do well without two non-values" argument doesn't mean that JavaScript should do the same; it just means that there's no need for JavaScript to specifically choose this solution to the problem.

If you want an actual reason not to have two non-values, it's that this just seems very arbitrary. Why two, why not three? And if you're ascribing more and more semantics to the different kinds of value-absence, shouldn't you also expose this possibility to the user? At this point, just let users define their own values that are treated as falsey by the language and add a FalseySymbol counterpart to Symbol.

 
scottshipp profile image
scottshipp

If you want an actual reason not to have two non-values, it's that this just seems very arbitrary.

I don't think it seems arbitrary at all. The language specification is not arbitrary when it describes null as meaning something explicitly set and undefined meaning something, well, undefined. Just because they both evaluate to "falsey" doesn't mean there's not a clear difference to their actual meaning. The reason those two exist (and not three or four or five) is because there's not another clear cut solidly-defined use case for it. But for both null and undefined, they both have a clear unambiguous meaning and plenty of use cases.

 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

You misunderstood my point; both null and undefined are not at all arbitrarily defined; what is arbitrary is exactly having two of them.

If you're going to distinguish non-values of different kinds, why only two? Why not add a third one for "no selection", or a NaN-like value for "unknown" values? And I'm sure many problem domains would come up with their own non-values that make absolute sense to distinguish from null and undefined.

As I said, at that point a more elegant solution would be adding FalseySymbol or NullishSymbol or both and leave it up for the user to define specific non-values that hold whatever semantic meaning they want.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

This is a neat case where there's exactly two reasons why a value could be empty. But in other cases there could be many different scenarios.

If you really want to use your own "empty" value, you can simply construct a symbol to represent that specific state

let no_selection = Symbol("User did not make a selection") // or just undefined
let undisclosed = Symbol("User prefers not to share this information")
Enter fullscreen mode Exit fullscreen mode
Collapse
 
matyasjay profile image
Matyas Angyal

Hi, I would strongly disagree with this statement. In my opinion you definitely want to use explicit null in many cases. The thing is, null is a quite handy tool if you use it properly (eg. "Hey, I want this value to be unset but defined!"). Also, I noticed you are considering typeof null === "object" as a bug, which really annoys me. It is not a bug and the reason is lying in the fundamentals of the language (prototypal inheritance). Please be careful with such a statement, since it is misleading and generally wrong! My apologies being short and not going into the details though. Happy new year!

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️
typeof null
// 'object'
Object.keys(null)
// Uncaught TypeError: Cannot convert undefined or null to object
Enter fullscreen mode Exit fullscreen mode

While this is by design and therefore not a bug, I think this combination of behaviours is what makes for a very bad design. If null is an object, then it should behave like one.

Collapse
 
loucyx profile image
Lou Cyx

But .... it is a bug, it was never patched because ... welp, that would break the web (like many other things).

My point is mainly: Why do you need to do that distinction, when they are both "nullish" values? How do you think languages that only have one or have no nullish values deal with this?

For me at least, is kinda like the chicken and egg, folks don't actually "need" null, they generally just find ways of using it. Just for your consideration, there is a disclaimer at the bottom of the article in which I clarify that "you don't need" doesn't mean "you should never use", is just like saying "you don't need fast food", meaning you can survive without using it and you should avoid defaulting to it to solve issues that you can solve with better tools.

Collapse
 
matyasjay profile image
Matyas Angyal

Sure, I'm considering it not-a-bug for the same reason, it is just the part of the language and you have to deal with it :) However, you can exploit its potential. I personally prefer using null over undefined when I want to consider an asset to be explicitly empty (but still defined in the scope of the current code). undefined is the default value for a non-existent value and I think it is unsafe to rely on this, because it can cause runtime errors more often (think of global window in Node environment). It's all about practices and personal preference. In my opinion, null is a handy stuff and I'm happy to use it.

 
loucyx profile image
Lou Cyx • Edited

It's all about practices and personal preference

100% agree with this! My series of "you don't need" is not about imposing my style, is more about making the readers wonder: Do I really need that? Or I'm just used to it? I used to be a C++ hardcore fan, class all the way, and my first entry in this series is saying that we don't need them because I feel happier not using them in JS/TS.

About undefined introducing bugs, the vast majority of them are solved with the good ?? and ?., so you can actually do stuff like:

const obj = {};

obj?.level1?.level2; // undefined, no errors
obj?.method?.(); // undefined, no errors

obj?.level1?.level2 ?? "default value"; // "default value", no errors
obj?.method?.() ?? 10; // 10, no errors
Enter fullscreen mode Exit fullscreen mode
 
matyasjay profile image
Matyas Angyal

Yup, exactly. Hail to nullish coalescing and chaining! I love how people eager to build the language forward and constantly improving it in every year. Classes are not quite making sense in JS to me too. Although, it is important to be able to adjust your personal preference to the environment your working in. Everyone is doing stuff differently, but we usually work in teams, so... you know the drill.

 
loucyx profile image
Lou Cyx

Indeed! My No.1 priority at work daily is making my teammates lives easier, building components, utils and libraries for them. More than once I had to change something I personally like to something that adjust to them better, and that's ok. They are all happy without having to deal with classes, but if they weren't, I would be doing classes even if I don't use them in my personal projects, just to adjust to them ❤️

Collapse
 
leob profile image
leob • Edited

No ... you're saying "folks that use it a lot ... get pretty mad" - I'm not mad at you lol ... but I still see value in explicitly assigning null, and undefined is a distinct case.

The point is that "undefined" is automatically there, while what I want is for programmers to explicitly and deliberately initialize their variables - be it to null, or zero, or an empty string, or whatever makes sense. But explicitly initializing a variable to "undefined" makes no sense (because by definition it already has that value).

If you really want to get rid of null pointers and of "having to check for null everywhere" then you should introduce an "optional" concept (like Rust has, or even Typescript).

Collapse
 
loucyx profile image
Lou Cyx

We have "optional" with JS, you just use default values (only works if the passed value is undefined), nullish coalescing and optional chaining (this last two work withnull as well). TS after all is just a superset of JS, the types it uses are just the explicit version of JS types (also seen in JSDocs).

Thanks for not getting mad. Trust me, there are some folks here pretty vocal about their opinions not matching with mine 😅

Collapse
 
leob profile image
leob

People should remain rational, getting all emotional over tech debates is a bit stupid lol

Collapse
 
scottshipp profile image
scottshipp

No matter how much you don’t want to use null you’re going to end up using it anyway. It’s going to come in from libraries, input, and data sources.

Collapse
 
loucyx profile image
Lou Cyx

You still don't "need" it, you'll just have to use it when you use those libraries. You can also use validation libs to turn nulls into undefineds. The important thing is avoid using it yourself in your code, not su much the contact surface with code outside your control.

Collapse
 
scottshipp profile image
scottshipp

You don't "need" stoplights but not knowing about and incorporating them into your driving will have disastrous results.

 
loucyx profile image
Lou Cyx

That's not a good analogy -_- ... I never said you don't have to know about nulls, how they work and how to deal with them if you find them, I said you don't need them in your code, and you are generally fine with undefined.

 
scottshipp profile image
scottshipp

I mean, you also haven't said to "deal with them if you find them" (which by the way means having null in your code).

 
loucyx profile image
Lou Cyx • Edited

Might be a language barrier that's complicating this conversation, but I said this already several times in the comments: You should keep null in the surface of contact with things that "need" null, like APIs. That means that you'll have to write null to interact with those pieces of code that didn't figured out how to work with undefined, yes ... but still doesn't mean you need to write null in the code that doesn't interact with those APIs.

[your code] <-> [API methods/functions] <-> [API that requires null]
Enter fullscreen mode Exit fullscreen mode

You can keep null in the block in the middle there, only. And in your code just use undefined. Think it this way, if you invite a celiac friend to eat outside, you need to buy something gluten free for them, but do you eat gluten free as well when you don't need to?

 
scottshipp profile image
scottshipp

You should keep null in the surface of contact with things that "need" null

It sounds nice, but null is part of the JavaScript language itself. It has an explicit meaning in the specification:

primitive value that represents the intentional absence of any object value

So that "surface area" you're talking about isn't going to be limited to APIs. And when you share a JS codebase with anyone else, the approach of not using null is going to be untenable, and, even if you don't share, your JS is not going to be idiomatic.

 
loucyx profile image
Lou Cyx

I mean, I worked for years now with different teams without using null, and nobody misses it or says "we could solve this with null". I said it on the article already, but making that distinction between "intentionally absent" and "unintentionally absent" doesn't make sense, because is just "absent" and you need to deal with it the exact same way.

 
scottshipp profile image
scottshipp

I mean, I worked for years now with different teams without using null, and nobody misses it or says "we could solve this with null".

That doesn't mean it's idiomatic.

said it on the article already, but making that distinction between "intentionally absent" and "unintentionally absent" doesn't make sense, because is just "absent" and you need to deal with it the exact same way.

I can see that it doesn't make sense for you, but look at all the commenters here with plenty of examples where it makes sense. And I even gave you one in another thread.

 
loucyx profile image
Lou Cyx

If we have to use this article as a metric, we have 10+ negative comments and 10+ folks liking those comments, so let's say 20+ total. And then we have 55 likes to the article itself, 17 unicorns, and 6 positive comments, so let's say total 70+ ... I knew I would have some folks that wouldn't agree (that happens with every article in this series). You keep saying is not idiomatic, and my point is that you're just saying "the same thing with two different words". The distinction is not needed, you might use null to make that distinction between two "optional" values, but you don't need null for that.

The point of the article is to actually make you think if you need it, I know some of you are used to using null or you do that unnecessary distinction between null and undefined, but the idea is to make you actually think if you need that distinction, or not. Have you actually tried to code without using null yourself? Maybe you already did, and you missed null every single day, but my experience (and the experience of many other folks) was the exact opposite.

 
scottshipp profile image
scottshipp

You keep saying is not idiomatic, and my point is that you're just saying "the same thing with two different words".

The point about idiomatic JavaScript has to do with working with JavaScript developers. If you write in a non-standard (not idiomatic) way, you make it harder for others to use your code or integrate with it, and that can lead to bugs.

The point of the article is to actually make you think if you need it

These reasons to use null seem compelling to me:

  • null is core to the JavaScript language--it's in the language specification and used in various language features
  • null is returned from data sources, user input, and third-party libraries and API's whether or not your code uses it
  • As a result, null is idiomatic JavaScript (leading to the point above)
  • null has a different meaning from undefined, which is significant, and the two cannot be used as substitutes of each other without creating ambiguity (null is used to show that the value was explicitly set, undefined is used to indicate that no value was ever set)
 
loucyx profile image
Lou Cyx • Edited

The point about idiomatic JavaScript has to do with working with JavaScript developers. If you write in a non-standard (not idiomatic) way, you make it harder for others to use your code or integrate with it, and that can lead to bugs.

How can use less ""features"" makes something lead to bugs? The only way of leading to bugs is if a dev assumes that something will have a null value, for example, and my function returns undefined instead ... but the same could happen the other way around :/ (not to mention both are solved the exact same way)

null is core to the JavaScript language--it's in the language specification and used in various language features

Being in the language is not a "compelling" reason, because we avoid things in the language all the time that we know are bad. eval and with are still part of core JavaScript, and you wouldn't use those because you know that they lead to issues of all kinds.

null is returned from data sources, user input, and third-party libraries and API's whether or not your code uses it.

I already said that you can then deal with null only when working with those. Not to mention that data sources can also return undefined, it depends on how are they made, and the actual user input is never null, you can get "null" of user input only if the handler for said input returns null.

As a result, null is idiomatic JavaScript (leading to the point above)

So for you idiomatic is: It's in the language + folks use it. From that definition, being "idiomatic" is not a good reason to use something from my point of view.

null has a different meaning from undefined, which is significant, and the two cannot be used as substitutes of each other without creating ambiguity (null is used to show that the value was explicitly set, undefined is used to indicate that no value was ever set)

I keep asking why is that distinction even useful? They are both missing values, both needs to be handled the same way ... so why is useful to differentiate one from the other?

 
scottshipp profile image
scottshipp

How can use less ""features"" makes something lead to bugs? The only way of leading to bugs is if a dev assumes that something will have a null value, for example, and my function returns undefined instead ...

Exactly. Consider the matches() method on string. It returns null to indicate that there are no matches found. Let's say we take your approach and wrap this in our own method where we return undefined for this case instead. Now you have a client of your method who is a JavaScript developer. They check for null to see if no matches were returned, but you have overwritten this with undefined. And that's a fairly benign case.

This is often known as the Principle of Least Astonishment or Surprise. Users of your code should have an expected experience.

 
loucyx profile image
Lou Cyx • Edited

Do you actually do if (matches === null) nowadays? You don't need a wrapper. You can use nullish coalescing and avoid a lot of pain with both null and undefined (again, you handle both cases the same way). So you can do something like this:

const [match] = "bar".match(/foo/) ?? [];

console.log(match ?? `Not found`);
Enter fullscreen mode Exit fullscreen mode

Which works with both null and undefined. Instead of having to write:

const matches = "bar".match(/foo/);

console.log(matches !== null && matches[0] !== undefined ? matches[0] : `Not found`);
// or relying on falsy
console.log(matches && matches[0] ? matches[0] : `Not found`);
Enter fullscreen mode Exit fullscreen mode

And I still don't see where the distinction between null and undefined is valuable here. With the same example of the util, if someone does a wrapper of something that generally returns undefined, and they make it return null, it could cause confusion as well. You should't code assuming the nullish output of a function, and you still can be resolved similarly to the above issue.

BTW, if I had to write a wrapper for match, I would do it something like this:

const match => regExp => string => string.match(regExp) ?? [];
Enter fullscreen mode Exit fullscreen mode

This way you can not only curry it, but always be sure you'll receive an ArrayLike from it instead of RegExpMatchArray | null which is far from ideal.

 
scottshipp profile image
scottshipp

Do you actually do if (matches === null) nowadays?

It seems that you asking this question proves the point. You have no idea what I (or other clients of your code) are going to do. I may do that or use the fact of matches returning null (and not undefined) in probably a few dozen different ways. And when/if you change that, you introduce the potential for bugs, as previously pointed out.

You don't need a wrapper.

The idea of a "wrapper" came from your comments, not mine, though.

And I still don't see where the distinction between null and undefined is valuable here. With the same example of the util, if someone does a wrapper of something that generally returns undefined, and they make it return null, it could cause confusion as well.

I am not sure but I'll give the benefit of the doubt here and assume that you are not willfully missing the point. So to reiterate again: yes that could cause confusion as well, and the very fact of this confusion is why JavaScript developers should not ask "Do I really need to use null?" and should, instead, use both null and undefined consistent with general practice. It is the standard practice (the idiom) in JavaScript for null to represent a purposefully-set value and undefined to represent a value that was never set, and this is in the language specification as well as the canonical books and documentation.

 
loucyx profile image
Lou Cyx

It seems that you asking this question proves the point.

My point was that you shouldn't assume the output of a function. In your previous comment you basically said that you "expect" something to return null. Based on your same logic in this new comment: "You have no idea what I (or other clients of your code) are going to do", so why is bad for me to assume you'll know that you shouldn't do matches === null, but is good for you to assume that the function will return null instead of actually checking the return type of the thing you're using?

And when/if you change that, you introduce the potential for bugs, as previously pointed out.

But that's the thing, if you use a function assuming it will return either null or undefined, why is it on me as the dev and not on you as the consumer of that function? I already said this, but the other way around your same argument applies, if you create a function that I expect will return undefined, and instead you decide that it will return null, then it's my problem that I was expecting your function to return something I wanted it to return, instead of checking the typing or using something like ??.

And I still don't see where the distinction between null and undefined is valuable here. With the same example of the util, if someone does a wrapper of something that generally returns undefined, and they make it return null, it could cause confusion as well.

I am not sure but I'll give the benefit of the doubt here and assume that you are not willfully missing the point.

Trust me, I'm giving you the same benefit. I added sources to the article for y'all to explore, because my personal experience of not using null in personal projects and at work, and not missing it at all, and explaining that the "distinction" between intentionally missing and unintentionally missing value is pointless because they are both missing and need to be dealt with the same way. Maybe checking some other sources besides my article adds some light to the subject, but if null is so necessary, how is it that Angular is considering dropping null, TypeScript doesn't use null in its source, and folks like Douglas Crockford, with years of experience in JS, don't use null at all and just use undefined instead?

As @darkwiiplayer pointed out several times already, that "need" for multiple nullish values is trivial, having 1, 2 or 10 different nullish values with differences you define with conventions, doesn't take back the fact that they are all still just nullish.

Every time I ask: Why do you need to do that distinction?

The answer is pretty much "because null exist in JavaScript for that", but that doesn't actually answer the question. There are several things that exist in JS to be used for something, and we realized that there are better ways to do that same thing and not use that feature (eval and with are the two that I mention constantly).

We might never agree on this, but the questions I leave to you are:

Do you actually tried to code without null at any point? Do you ever worked with a library/framework or codebase without null and missed having it? Because I sure did tried doing it "your way" in the past, and once I did the "transition" I never went back.

Collapse
 
vladivo profile image
vladivo • Edited

A valid use case for null is when you want to iterate over object properties and do some logic if corresponding values are empty. You usually don't want to write things like typeof string && "". What about numbers? What about booleans? Angular for instance uses it in its Forms Module. If a non-string field is empty, its value is null. If you reset any field value its default is null. So to me null is absolutely legit and not synonymous to undefined.

Collapse
 
loucyx profile image
Lou Cyx

You usually don't want to write things like typeof string && ""

That doesn't make much sense for me. If something can be either string | undefined, then adding | null to the mix doesn't help much here. You end up having to test for yet another type, when you could just keep it simple.

This two behave exactly the same:

Object.entries({
    number: null,
    boolean: null,
    string: null,
}).map(validate);

Object.entries({
    number: undefined,
    boolean: undefined,
    string: undefined,
}).map(validate);
Enter fullscreen mode Exit fullscreen mode

So validate there could be implemented like this:

const validate = ([key, value]) => `${key} is ${value ?? "nullish"}`;
Enter fullscreen mode Exit fullscreen mode

Which would work exactly the same for both null and undefined. What's the advantage of null over undefined here?

And about the argument of "Angular uses this in its Forms Module", just because a module/library/package uses null, that doesn't mean that you need to use null all over your app as well. Not to mention that if a non-string field is empty, it could be undefined as well, same if you reset it, is just an implementation detail of that forms module, which doesn't mean you need to use null in places where you're not interacting with that particular module.

Collapse
 
vladivo profile image
vladivo

Good points! My examples were not that good. Still, in some other place of my program I might want to directly access the object property like foo.bar and if it is undefined how can I be sure that the property even exists? I mean they are semantically different and have slightly different behaivior and I embrace them both as features of the language. You are correct in your wordplay, you don't need null, but I want to extend this and say that you may want it. For consistency, readabitity, because of business requirement or for whatever other reason. This is not a "goto"-situation. If you choose wisely your code will only get better. Like in Typescript there are types any and unknown which are in many cases interchangeable without any side effects, but... unknown is safer and sometimes you really need any.

 
loucyx profile image
Lou Cyx

You might be one of the first devs to comment here with the "opposite view" but you actually understood the post 🤣 ... Indeed, the idea is that you don't need null and you can use undefined to express the same things better, but if there's a library that only works with null, then you have to use it there. The main idea is that we shouldn't default to null and just use it when is actually necessary. Some folks think is necessary to make a distinction between null and undefined and I (and many other devs) disagree with this because they both represent a "no-value" or "nullish", but that doesn't mean "you should never use null", that only means "you should use it when is actually necessary", like APIs or libs that only work with null.

About any vs unknown, I might write a "you don't need any" showing how you can use unknown everywhere, safely, even if you want to be lazy as you'll be using just any ☺️

 
vladivo profile image
vladivo

I might be wrong, of course, but I am still not as convinced as you are. They are simply different and we would probably have quite heated debates regarding some special cases if we were working in same team. And I would also install a swear jar for such words like "nullish" or "falsy". My code is strict and explicit af 😄

Although, to be completely honest, I also have to admit that we really did forbid null in our previous project and mapped all null values as undefined in all our API responses. Didn't regret this decision, in our case (with good models) undefined worked as "empty value" really good, felt natural and the only places where null was really inavoidable were API and Angular forms.

Btw, I have a good example where you really need any. It's JSON:API standard which defines one of the fields as object, so the best you can do on the most abstract level (before any extensions with type narrowing) is something like Record<string, any>.

 
loucyx profile image
Lou Cyx

But you could also do Record<string, unknown>, which is like saying: I know this is an object, I just don't know the type of the properties inside of it ... way better than having any and accidentally calling a method or passing it to a function without first checking what that is. I see unknown as strict any, you can't use it unless you first figure out what it is. And I love it.

I also code pretty strictly and I still see not benefit using null at all (unless, as we said already, I'm interacting with something that needs null). And I share that experience you had, of migrating codebases to only using undefined, or having that no-null ESLint rule, and the best thing about that experience is that not only me, but nobody in those teams missed null (that's also why I shared that talk given by Douglas Crockford, because he had the same experience, years ago).

 
vladivo profile image
vladivo

You're right. And I am stupid. Of course, unknown can be narrowed same as any. Simply forgot that.

 
loucyx profile image
Lou Cyx

You're not stupid! I used to use any quite a lot before unknown was introduced, so it's ok if you're still checking before using it. The main difference is that unknown forces you to do that check, but if you still do it is ok!

 
vladivo profile image
vladivo

The thing is that today I really never use any (except for Angular and such). Absolutely forbidden! But I also wrote the implementation for jsonapi before I learnd unknown. So... 🤷😄

 
loucyx profile image
Lou Cyx • Edited

That's what happen to folks like us that were in this TypeScript game for a long time x'D

Collapse
 
grahamthedev profile image
GrahamTheDev • Edited

Definitely food for thought!

I personally over rely on null as it works so nicely with databases, but that is just laziness on my part and you are right that stripping null values instead of validating them (which does require some thought so you don’t open a massive security hole) does seem cleaner!

Next side project going to give this a go!

Now can you please stop this series as I am running out of things I can use! 😜🤣

Collapse
 
loucyx profile image
Lou Cyx

Let me know if you hit any wall while trying to get rid of those nulls, and I'll do my best to help out. In my personal experience I even noticed some speed bumps in requests/responses because payloads were always smaller 🎉

Collapse
 
grahamthedev profile image
GrahamTheDev

Thanks Luke, great to know as I am sure there will be something and I imagine there won’t be much out there in terms of advice on something like this! 👍

Collapse
 
mistval profile image
Randall

I've seen people give entire lectures about when you should use undefined and when you should use null. I always found that a bit silly. We have better things to waste our attention on. I just always use undefined unless forced to do otherwise (by some library that does === null or such).

Collapse
 
atemiz profile image
Ahmet Temiz

I try to use undefined wherever possible. However, null can be useful for asynchronous operations. For example, if the user object is undefined, the initialization phase has not been completed yet. Otherwise it's ready to use. If null, there is no user. Login is required.

Collapse
 
patroza profile image
Patrick Roza • Edited

Patch api; omit (which is usually synonymous to undefined) is “not changed”, null is empty value.

You took string as an example, but think also about numbers (-1?) or objects etc

Collapse
 
loucyx profile image
Lou Cyx

We could change our API handler functions/methods in the front-end so when they do a patch operation we turn the intentional unset values into nulls that the back-end will understand. Still, an API that uses null from the front-end to clear values in the back-end doesn't look like a great idea in general. Ideally you should have some kind of option in the endpoints to unset values, if we have updates and unsets in the same patch endpoints it feels like an accident waiting to happen.

Collapse
 
patroza profile image
Patrick Roza

What’s the difference between an unset and an update?

 
loucyx profile image
Lou Cyx • Edited

With update you're just changing one value with other, while unset is closer to the DELETE operation. In graph based DBs like DGraph, or No-SQL DBs like Mongo, is quite dangerous to just unset a property of something. Let's say accidentaly you set this with a PATCH:

{
  "user": "lukeshiru",
  "friends": null
}
Enter fullscreen mode Exit fullscreen mode

And friends was an array containing all the friends of said user, suddenly we deleted all friends in a patch operation. Ideally actions like that should be in a different endpoint, not the same one you use for updates (not to mention this wouldn't even be possible if we don't use null at all).

 
patroza profile image
Patrick Roza • Edited

What about
totalCost: {
amount: 50,
currency: “EUR”
}

Just creating a sub resource for totalCost to be able to delete it, is not really optimal.
Not to mention you may use it in an atomic batch of changes

 
loucyx profile image
Lou Cyx • Edited

But in that scenario, for example ... why would you set totalCost to null? The default should be { amount: 0, currency: "EUR" } or something like that. If you want to leave the default, you omit it, if you want to update it to the default then you just set it to {} (maybe even the wrapper function you have to deal with API interactions can do that for you), and when you want to set a value then you just set it { amount: 50 } or just the currency { currencty: "USD" } or both { amount: 50, currency: "USD" }.

My point when talking about this in the article was that when you need null, you actually need a Type | null, which can be easily replaced with Type | undefined or even just Type because maybe you didn't even needed that nullish in the first place.

Don't take my word for this, you can just google about languages with a single nullish value or without them, and see how they solve this issues ... that can be easily transferred to JS, using only undefined 😄

 
patroza profile image
Patrick Roza • Edited

We certainly could do that, but it would violate the business needs.

We can use custom null objects to mean no-value, but why? Just to reach a metric of not using null?

Another way is to represent Options or Maybes or Eithers as tagged unions, but if you have null at your disposal, and mind you, it is part of the json spec, so even languages without null or with just one nullish value, can still leverage absence (aka undefined), and null when speaking json.
It certainly makes interacting with your api easier and more standard :)

How you interpret these values while deserialising json, or when you play the object dance in domain model, or how to store and represent in your persistence model; those are private implementation details.

 
loucyx profile image
Lou Cyx

We might not be understanding each other, if the API needs null to work, then use it when interacting with it. The article doesn't say "you should never ever use null", the point of the article is that we shouldn't default to it and use undefined instead. Instead of having null and undefined all over the code, you should use just undefined in your code, and if the API is limited to using null, then just use null in the functions or methods that interact with it.

I have a disclaimer at the bottom of every article in this series because folks generally understand "you don't need" as "you should never use", and that's not the point. This series is about re-evaluating our defaults.

Collapse
 
darkwiiplayer profile image
𒎏Wii 🏳️‍⚧️

There would be more of a case for null/undefined as separate values if something like this:

{key: "value", ...{key: undefined}}
Enter fullscreen mode Exit fullscreen mode

actually worked, that is, returned {key: "value"}; but instead, JS still treats undefined in the second object as different from not setting a value at all, which makes this whole distinction very pointless.

Collapse
 
anonyme profile image
Info Comment hidden by post author - thread only accessible via permalink

Api to update profile details have several optional fields. One of them is display name.
Null = no special display name, use account name. If there was a display name, replace it with null.
Omitted = don't change display name.
String = new display name to use.

Now you just entered the realm of "let's use ugly tricks to represent null like 'empty string'" or add another field that says 'delete name'. Used empty string? Congratulations you can no longer use standard name validations (that usually occur before your api handler) because you'll get name too short or empty before even doing your ugly hack that treat empty as null.

Null have a contract meaning. Now you'll answer me like you answered everyone else "just use undefined bro" because honestly reading your comments it sounds like you dont even listen to what people try to teach you.

Go ahead, write poorly designed APIs. I'll use null, thank you.

PS and that "let's save few bytes" argument is something a junior dev would say. It's meaningless. If you really care about it use compression. Or better, use binary format and not json. But if you chose json go with proper json and don't uglify it to save few bytes. If your api use json it means you are OK with the extra overhead otherwise you wouldn't use json, and being cheap in few bytes is absurd.

That's like copy-paste the same line 10 times instead of using for, to save the for() overhead....

Collapse
 
loucyx profile image
Lou Cyx

Now you just entered the realm of "let's use ugly tricks to represent null like 'empty string'" or add another field that says 'delete name'. Used empty string? Congratulations you can no longer use standard name validations (that usually occur before your api handler) because you'll get name too short or empty before even doing your ugly hack that treat empty as null.

So you find "" and the type string? uglier than null and the type string | null | undefined? I guess we agree to disagree. And that second part about validations, what is that you can't validate about a string if is empty? I mean if you use null the validation might look like this:

if (displayName !== undefined) {
    if (displayName === null) {
        // use account name
    } else if (validate(displayName)) {
        // set new display name
    } else {
        // invalid new display name
    }
} else {
    // Don't change display name
}
Enter fullscreen mode Exit fullscreen mode

And look at this huge change if you used an empty string instead:

if (displayName !== undefined) {
    if (displayName === "") {
        // use account name
    } else if (validate(displayName)) {
        // set new display name
    } else {
        // invalid new display name
    }
} else {
    // Don't change display name
}
Enter fullscreen mode Exit fullscreen mode

Null have a contract meaning. Now you'll answer me like you answered everyone else "just use undefined bro" because honestly reading your comments it sounds like you dont even listen to what people try to teach you.

I mean, that being the case, you wrote a comment like everyone else pointing to this single problem with patch like APIs, when the article is about avoiding null as much as possible:

  • The article: You should avoid using null everywhere, when undefined is perfectly fine.
  • You: No, because of this particular use case.

IDK about you, but everywhere !== somewhere. And my answer is always the same because you're pointing the same thing. My answer would change if the comments where different. I explained it in the article itself, but is weird that you need to type everything as Type | null | undefined, like you need 3 different states for everything, when other languages are perfectly fine with 2 (Type | nullish).

Go ahead, write poorly designed APIs. I'll use null, thank you.

OK, go ahead and keep using it, I guess your answer to my question in the article is that because is useful in this patch like scenario, then you have to use null everywhere. I already explained that you could keep null in the contact surface with the API only, and avoid it everywhere else, but I guess that's not enough null for you 😅

PS and that "let's save few bytes" argument is something a junior dev would say. It's meaningless. If you really care about it use compression. Or better, use binary format and not json. But if you chose json go with proper json and don't uglify it to save few bytes. If your api use json it means you are OK with the extra overhead otherwise you wouldn't use json, and being cheap in few bytes is absurd.

Of course you had to go and say "You're a junior if you don't do things like I do them". JSON parsing is really fast, but skipping nullish values is faster not only because of the actual transfer from the back-end, but also because of the parsing itself. So you're making your responses smaller, your requests smaller, your parsing faster and your type checking easier, not to mention testing which doesn't need to check for 3 different types. But let's better use null because is less "ugly" and junior-like, right? 🤔

That's like copy-paste the same line 10 times instead of using for, to save the for() overhead...

Talking about for, you might not like my other article talking about it 😅

Collapse
 
anonyme profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Anonyme • Edited

EDIT: lol you got utterly btfo so you hid my comment and blocked me from writing new comments? Coward. Hope you at least learned something.


EDIT 2: you're still a coward and continue to reply to me while I'm blocked. but you don't even worth the comment I wrote. bye.


Second reply below, before I saw you blocked and edit this:

  1. Im talking about null in js and you answer in typescript. If you want to talk about typescript say "you should not use null when using typescript". Your article seems to be talking about js and ts alike.

  2. Are you really that much of a junior that you actually write your api json validations manually with if-else, and not using a proper schema validators? Have you never written any API before or are you just being dishonest when presenting your "solution"?

  3. You wrote your article in a very strong, clickbaity tone, then you go and hide behind that tiny disclaimer in the end. Stop acting innocent. You wanted to write an edgy and controversial opinion? Own it! And if you can't or don't have the balls to do so, don't write so boldly. Just say "why you should sometimes prefer undefined over null". But that's not cool and edgy and click bait enough isn't it? So you want to eat the cake and have it too, by putting your little disclaimer in the end. Real mature.

  4. Which brings me to the next point - why I insist on putting you back in place - I know juniors like you, you try to make a name of yourself by spewing out controversial edgy nonsense that may sound like they make sense, but are actually really bad. Problem is, other juniors pick up this nonsense and repeat it to sound cool and end up writing bad code because of that. Much smarter and experienced people than you decided null was necessary. There's a reason for that. You don't have to try and butcher every holy cow just for the sake of it.

  5. Json is not extremely fast, it's extremely slow compared to pushing bytes array, but its fast enough for most APIs which makes it ok. When you choose JSON for your API you make the decision of readability over performance, and that's OK for 99% of cases because json fast enough. But if you made that decision, you don't turn back and later uglify your entire API just to do tiny optimization. That's something a junior would do. Either your API is performance critical in which case you dont use json at all, or its not in which case you try to keep it clean. I mean, you don't rename keys from 'userName' to 'un' just to save few bytes right? That's equally dumb than omitting fields that should be null, and probably save a lot more bytes. But I do hope you don't actually do that...

In summary- nulls are useful, stop trying to sound edgy then run back to your disclaimer, and you dont sacrifice readability for performance when using json.

 
loucyx profile image
Lou Cyx • Edited

I know you're new here, but the community of DEV is based on respect for each other, even if you don't agree with something, you keep it respectful. You already started saying this was "ugly" and the solution was "junior", but I let that pass because you're new and maybe it was a language barrier ... but then you went and insisted with the junior thing, "lack of balls", being immature, which was more ad hominem than an actual argument. To top it all out, you added that "coward" thing when you noticed you got blocked.

If you don't want to keep getting blocked by other users or banned from DEV altogether, I suggest you lower that a notch.

Cheers!

Collapse
 
adam_cyclones profile image
Adam Crockett 🌀

Oh I used to care about this stuff, I don't think I do anymore but your post captures the arguments exactly. I don't care so much because I know how wild JavaScript is about falsely and truthy values compared to other languages. Best not to loose sleep over it 😅

Collapse
 
loucyx profile image
Lou Cyx

You should never loose sleep over anything code related, even more so if that code is JS 🤣 ... the articles in this series are more like "thought experiments" to make the readers wonder if they really "need" given thing to code, of if maybe it makes sense to not use that. I share the things that make me generally happier when coding, but that doesn't mean it will make everyone happier (as proven by some quite vocal users, raging on the comments 😅).

Collapse
 
adaminbiriistee profile image
ordinary guy

Good explanation.

Collapse
 
ffind profile image
Info Comment hidden by post author - thread only accessible via permalink

These toxic pointless posts with title like "you should never ever use.." should banned from self-respecting tech publications.

Javascript is grownup language, and everything regarding it is already written in nice books and articles. Stop inventing a wheel, discover America, recreate alphabet with posts like this. Either add something valuable, innovative or stfo.

It is my first comment in Dev. As a JS veteran I regret spending time on this post.

Happy New Year!
Best wishes to you op, hope you won't be offended.

Collapse
 
posandu profile image
Posandu

Good article.
Cheers!

Collapse
 
deathshadow60 profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Info Comment hidden by post author - thread only accessible via permalink
deathshadow60

Somehow it would figure someone making ill educated and nonsensical claims about something we "don't need" would be suggesting linters. Given the endless wreck of nonsense they seem to like by default like kvetching about Yodish, drop-through on case, and so forth. The stuff linters seem to do is all silly pet peeves of people who don't seem to actually know how to program, or screaming "I'm too dumb to understand this, so nobody else should be allowed to use it.".

Reinforced by the titles of your other "You don't need" articles, and how each of them jumps through some crazy hoops of fire for the bloated alternatives.

Collapse
 
konferbe profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Info Comment hidden by post author - thread only accessible via permalink
Steve Lebleu

Sad. Very, very sad. You can debate and argument about that, but the only reality is that null and undefined are completely different, and should be used differently. No more no less. The rest is trolling.

Collapse
 
loucyx profile image
Lou Cyx

Ohh yes, the good ol' "I'm right, the rest is wrong" argument without actually adding anything to the conversation. Maybe when you said "the rest is trolling" you were making a reference to your own comment? 😅

Collapse
 
konferbe profile image
Steve Lebleu

I spend a little bit of time to read all comments, and as I see you spend a lot of time to explain the unexplainable. Other people have responded about the differences between null and undefined, and each time you come with tadam, but no ... Null is defined without value, undefined is not defined. So, what else ?! .. :)

 
loucyx profile image
Lou Cyx

So you read the post, read the comments and then added your own just to say "sad very sad" instead of explaining why from your point of view that distinction is useful at all, and how other languages that don't have two nullish values survive? .... Ok, thanks I guess, commenting boost the visibility of a post, but maybe next time try to engage in the conversation so others can learn from you and you can learn from others...

 
t0m4 profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Info Comment hidden by post author - thread only accessible via permalink

An arrogant developer is the worst kind... Dude you are not right, accept it. So you think all who contradicts your opinion are stupid? :D Hope you do coding as a hobby!

Collapse
 
t0m4 profile image
Comment marked as low quality/non-constructive by the community. View Code of Conduct
Info Comment hidden by post author - thread only accessible via permalink

So thats why you are censoring comments? The truth hurts?

-- edit --
I'm reading this site for years and most of the juniors are humble enough, and here you come, kicking in the door with this amount of arrogancy and to possibly teach others bad practises, you are disrespecting us with this.
You are also confirming all these with the blocks... You know @anonyme was 100000% right and all you did was getting offended instead of learning from more experienced people.

I guess you are the one who tries to justify bad stuff when you get a PR comment.

 
loucyx profile image
Lou Cyx • Edited

There's a code of conduct against disrespectful comments, and you created an account just to comment something that doesn't add anything to the conversation just is plain old Ad hominem. Forgot to block you, sorry about that. See you!

Some comments have been hidden by the post's author - find out more