If null means something doesn't exist, is there a reason for a function to ever return undefined? If I ever got an undefined back from a function, should I assume something went wrong and throw an error?
I would need to take existing values, check them for null, then create new undefined variables if i want to make use of ES6 default parameters. Seems messy.
It seems to be no drawbacks to just use undefined instead of null everywhere. Less code and easier to follow variables.
Yes, there actually is. Map#get returns undefined when you attempt to access a key value that hasn't been defined. You can explicitly set a key to null and have it return null, though, but would be intentional on the programmer's part. I wouldn't consider this to be some error. I think it's rather intuitive. It's consistent with how objects return undefined when a key/property hasn't been defined in itself and its prototype chain.
I'm not quite sure if I follow what you mean by this. Can you please rephrase it? Or provide a concrete example?
Well, as said in the article, it is true that there aren't really any drawbacks for choosing null over undefined, but it sure does help in keep code consistent with the languages's semantics, which in turn potentially results in more maintainable code.
#2 is presumably referring to the issue that passing null to a function with a default argument does not result in the default being used:
function returnNull() {
return null;
}
function returnExplicitUndefined() {
return undefined;
}
function returnImplicitUndefined() {
return;
}
function functionWithArgumentDefault(text = 'something') {
console.log(text);
}
function functionWithArgumentDefaultAndNullFallback(text = 'something') {
// suddenly default args don't seem so useful
const output = text !== null ? text : 'something';
console.log(output);
}
functionWithArgumentDefault(returnNull()); // null
functionWithArgumentDefault(returnExplicitUndefined()); // 'something'
functionWithArgumentDefault(returnImplicitUndefined()); // 'something'
functionWithArgumentDefaultAndNullFallback(returnNull()); // 'something'
Of course it's possible that you may want to output something different in the case of a null input; but this is definitely an issue that can catch people out...
edited: made function names more explicit and added a note.
Yes. Did you try running the code? It demonstrates precisely what I described. It's not uncommon to use the return value from one function as the calling argument in another. In this case returning null negates the usefulness of the default argument; since you still need an explicit check for null in the function body if you want to return the default.
I'll update the function names to make the example clearer; and add another possibility ;)
Anyway, I would argue that that's correct and reasonable behavior because null was explicitly passed in as an argument, whereas passing undefined as an argument would implicitly call upon the default value to be used as the definition in stead.
This goes back to what I said in the article where null communicates the express intent to pass absolutely nothing, whereas undefined communicates the absence of a definition. null does not, in fact, negate the usefulness of the default value if used correctly in this context.
So, really, the only issue in this code snippet is its noncompliance with the semantics of the language, which is what brings about the "issue" you presented in the first place.
I agree that passing null to a function does show an explicit intent that is different to not passing an argument... But I think the original question - and certainly my example code - relate to whether a function should return null or undefined to represent a falsy value; given that returning null then makes it impossible to leverage default arguments. You seem to be suggesting that null is always more appropriate.
I'd tend to use null if the failure of a function to return something is going to block further execution; so yes - in the context of document.getElementById it makes sense since you presumably want to do something with that element once you retrieve it and there isn't going to be an obvious default. But in other contexts the returned value may not be essential for things to keep running; in which case I'd argue that undefined is totally appropriate. Of course, right now, I can't think of a good example :shrug:
Okay, your argument is much clearer to me now. Thanks for the clarification. I now see the issue of returning null in this case.
For me, I'd still like to believe that even though the default parameter has been rendered useless due to the return value of null (as you presented in the snippet), the omission of the default value is still is semantically correct given that an intentional null was passed as an argument as the definition of the parameter.
However, I do agree about how it has basically made the default value useless, especially if one expects JavaScript to "fall back" to a default value if the argument passed in is a falsy value.
To appease both of our equally valid arguments, I'd say that we should refrain from using defaulted parameters as mere "fallbacks" to falsy values. For me at least, semantically speaking, the default parameter has always been there to allow a function to be executed despite having some of its parameters not being defined upon invocation. By restricting ourselves to only using default parameters when an invocation lacks all arguments, we can avoid the issue you presented since null would never be treated as a falsy value that needs a "fallback" in the first place (since null is the definition itself).
But I can see how my compromise may seem unsatisfying, to be honest. To that I say, "to each its own". Each of us has our own coding styles and philosophies. For me, I would never treat null as a falsy value that needs a default because I interpret null as a sufficient definition in itself.
TL;DR:null is not supposed to have a "fallback" in the first place.
Agreed: I think I already said that it makes sense for null not to have a fallback ;)
Anyway, I had time to think of some examples to illustrate when it may make more sense to return undefined from a function:
a helper function to select an optional property that may be deeply nested on an object. If I try and directly access an object property that doesn't exist I get undefined. It makes more sense to me to also return undefined from my helper function than to explicitly return null
a function that processes some form of optional input. If input is not provided it is undefined. In this case I'd be inclined to also return undefined
In both these cases it may be desirable to allow another function that accepts these return values to provide a default fallback.
To be clear: these comments aren't intended as criticism. I found your article interesting; especially since misunderstanding of falsy values and coercion often lead to unintended errors - e.g. the common use of the shortcut if(someValue) to determine that a value is defined falls flat when dealing with numerical input that may be 0...
But I also thought @tom
's question was justified. I think the confusion comes from this line in the article:
It is for this reason why null is more correct and desirable than undefined when returning nothing.
Was that intended to be meant specifically in the context of an object search; or as a general directive for returning nothing from any function? I'd disagree with the latter assertion for the reasons outlined above: I'd argue that context is more important in determining what is a semantically correct falsy value to return than having a rule that is set in stone: "never say never" ;)
Oh, no! Don't worry about it. I take no offense because I know that this is an educated discussion. 😉
As for the examples you provided, I definitely agree with them. I think it semantically makes sense to return undefined in your examples since the values of the fields haven't been defined in the first place. In other words, what I'm trying to say that your usage of undefined is truly valid and justifiable in those specific contexts.
In regard to the quote you cited, I see now how my wording can be misinterpreted and may have implied that undefined is "always" wrong. That is my mistake. When I wrote the sentence you quoted, what I meant by it is that null should always be returned if the intent is to literally pass absolutely nothing.
Software Engineering Manager focusing on React and Rails. Family of three 👨👩👦 from Taiwan/Costa Rica/Moscow 🇹🇼🇨🇷🇷🇺.
Lazy learner of languages: Español + English + 中文 + 日本語.
function isOddNumber(num) { return num % 2; }
function isOddNumber(num) { return Boolean(num % 2); }
In my case, I find that:
function isOddNumber(num) { return (num % 2 !== 0); }
Is even more clear than an explicit Boolean conversion. I'm also not a big fan of !!value, as when codebase grows, it becomes hard to skimp through the code.
Software Engineering Manager focusing on React and Rails. Family of three 👨👩👦 from Taiwan/Costa Rica/Moscow 🇹🇼🇨🇷🇷🇺.
Lazy learner of languages: Español + English + 中文 + 日本語.
That's just a microoptimization to be completely honest.
And I never used Boolean as a constructor. If I did, I would've used the new keyword. The way I used Boolean is merely a normal function call (like any other function call) to explicitly convert a value to a boolean. It's vaguely similar to how Object#toString converts any object to a string.
For further actions, you may consider blocking this person and/or reporting abuse
We're a place where coders share, stay up-to-date and grow their careers.
If null means something doesn't exist, is there a reason for a function to ever return
undefined
? If I ever got anundefined
back from a function, should I assume something went wrong and throw an error?I would need to take existing values, check them for null, then create new undefined variables if i want to make use of ES6 default parameters. Seems messy.
It seems to be no drawbacks to just use
undefined
instead ofnull
everywhere. Less code and easier to follow variables.undefined
when you attempt to access a key value that hasn't been defined. You can explicitly set a key tonull
and have it returnnull
, though, but would be intentional on the programmer's part. I wouldn't consider this to be some error. I think it's rather intuitive. It's consistent with how objects returnundefined
when a key/property hasn't been defined in itself and its prototype chain.Well, as said in the article, it is true that there aren't really any drawbacks for choosing
null
overundefined
, but it sure does help in keep code consistent with the languages's semantics, which in turn potentially results in more maintainable code.#2 is presumably referring to the issue that passing
null
to a function with a default argument does not result in the default being used:Of course it's possible that you may want to output something different in the case of a
null
input; but this is definitely an issue that can catch people out...edited: made function names more explicit and added a note.
I'm not quite sure if the snippet you attached is correct. Did you mean to invoke the function
baz
in the last line of the snippet?Yes. Did you try running the code? It demonstrates precisely what I described. It's not uncommon to use the return value from one function as the calling argument in another. In this case returning
null
negates the usefulness of the default argument; since you still need an explicit check fornull
in the function body if you want to return the default.I'll update the function names to make the example clearer; and add another possibility ;)
Apologies. I misread the code.
Anyway, I would argue that that's correct and reasonable behavior because
null
was explicitly passed in as an argument, whereas passingundefined
as an argument would implicitly call upon the default value to be used as the definition in stead.This goes back to what I said in the article where
null
communicates the express intent to pass absolutely nothing, whereasundefined
communicates the absence of a definition.null
does not, in fact, negate the usefulness of the default value if used correctly in this context.So, really, the only issue in this code snippet is its noncompliance with the semantics of the language, which is what brings about the "issue" you presented in the first place.
I agree that passing
null
to a function does show an explicit intent that is different to not passing an argument... But I think the original question - and certainly my example code - relate to whether a function should returnnull
orundefined
to represent a falsy value; given that returningnull
then makes it impossible to leverage default arguments. You seem to be suggesting thatnull
is always more appropriate.I'd tend to use
null
if the failure of a function to return something is going to block further execution; so yes - in the context ofdocument.getElementById
it makes sense since you presumably want to do something with that element once you retrieve it and there isn't going to be an obvious default. But in other contexts the returned value may not be essential for things to keep running; in which case I'd argue thatundefined
is totally appropriate. Of course, right now, I can't think of a good example :shrug:Okay, your argument is much clearer to me now. Thanks for the clarification. I now see the issue of returning
null
in this case.For me, I'd still like to believe that even though the default parameter has been rendered useless due to the return value of
null
(as you presented in the snippet), the omission of the default value is still is semantically correct given that an intentionalnull
was passed as an argument as the definition of the parameter.However, I do agree about how it has basically made the default value useless, especially if one expects JavaScript to "fall back" to a default value if the argument passed in is a falsy value.
To appease both of our equally valid arguments, I'd say that we should refrain from using defaulted parameters as mere "fallbacks" to falsy values. For me at least, semantically speaking, the default parameter has always been there to allow a function to be executed despite having some of its parameters not being defined upon invocation. By restricting ourselves to only using default parameters when an invocation lacks all arguments, we can avoid the issue you presented since
null
would never be treated as a falsy value that needs a "fallback" in the first place (sincenull
is the definition itself).But I can see how my compromise may seem unsatisfying, to be honest. To that I say, "to each its own". Each of us has our own coding styles and philosophies. For me, I would never treat
null
as a falsy value that needs a default because I interpretnull
as a sufficient definition in itself.TL;DR:
null
is not supposed to have a "fallback" in the first place.Agreed: I think I already said that it makes sense for
null
not to have a fallback ;)Anyway, I had time to think of some examples to illustrate when it may make more sense to return
undefined
from a function:undefined
. It makes more sense to me to also returnundefined
from my helper function than to explicitly returnnull
undefined
. In this case I'd be inclined to also returnundefined
In both these cases it may be desirable to allow another function that accepts these return values to provide a default fallback.
To be clear: these comments aren't intended as criticism. I found your article interesting; especially since misunderstanding of falsy values and coercion often lead to unintended errors - e.g. the common use of the shortcut
if(someValue)
to determine that a value is defined falls flat when dealing with numerical input that may be 0...But I also thought @tom 's question was justified. I think the confusion comes from this line in the article:
Was that intended to be meant specifically in the context of an object search; or as a general directive for returning nothing from any function? I'd disagree with the latter assertion for the reasons outlined above: I'd argue that context is more important in determining what is a semantically correct falsy value to return than having a rule that is set in stone: "never say never" ;)
Oh, no! Don't worry about it. I take no offense because I know that this is an educated discussion. 😉
As for the examples you provided, I definitely agree with them. I think it semantically makes sense to return
undefined
in your examples since the values of the fields haven't been defined in the first place. In other words, what I'm trying to say that your usage ofundefined
is truly valid and justifiable in those specific contexts.In regard to the quote you cited, I see now how my wording can be misinterpreted and may have implied that
undefined
is "always" wrong. That is my mistake. When I wrote the sentence you quoted, what I meant by it is thatnull
should always be returned if the intent is to literally pass absolutely nothing.Great read!
function isOddNumber(num) { return num % 2; }
function isOddNumber(num) { return Boolean(num % 2); }
In my case, I find that:
function isOddNumber(num) { return (num % 2 !== 0); }
Is even more clear than an explicit Boolean conversion. I'm also not a big fan of !!value, as when codebase grows, it becomes hard to skimp through the code.
Cheers! :)
Yes, that definitely works, too! However, I believe you meant
num % 2 !== 0
, though, since we're checking if a number is odd.Either way, I get your point. That's a valid way of thinking about it rather than the explicit and rather bulky
Boolean
call.Ooops, yes, edited my post :)
!!
is faster: jsben.ch/yVcTIAlso it warns about using
Boolean()
as a constructorThat's just a microoptimization to be completely honest.
And I never used
Boolean
as a constructor. If I did, I would've used thenew
keyword. The way I usedBoolean
is merely a normal function call (like any other function call) to explicitly convert a value to a boolean. It's vaguely similar to howObject#toString
converts any object to a string.