-
Notifications
You must be signed in to change notification settings - Fork 23
Strong evidence for treating null and undefined the same #20
Comments
I would prefer that they not be treated the same. The behavior used for default parameters is ideal IMO. If I set a value to JS is in a somewhat unique place having two distinct “null-like” values, and I wouldn’t want to lose the advantages of that by having the language unilaterally treating them as the same thing. With regard to the connection to default parameters: I’ll just say that I would intuitively expect the following two bits of code to be equivalent: function(a = 812) {
print(a);
} Versus function fn(a) {
a = a ?? 812;
print(a);
} |
@ljharb I think that issue only relate to iteration protocol and spread operator. |
@Has the issue is indeed, but the research results are broadly applicable. |
But it seems the table only cover the usage of iteration protocol (the constructor usages may be exception, but awb already explained that: tc39/ecma262#1069 (comment) ) |
Sure. But they’re still examples of many places where the language treats null and undefined the same, which is the relevance to this proposal. |
Ok, we may need a much bigger table to collect all the behaviors... As my understand, |
I think that the traditional use of null/undefined is not a very important thing to consider in order to decide the semantics of
In those cases you might or might not find a convincing reason why ”no value” is encoded precisely as undefined, respectively null; it doesn’t matter, because you don’t care when your goal is to provide a fallback. Also, the two major cases I know where the distinction between undefined and null is important and indeed useful, namely JSON stringification and defaults, are situations where you provide a value, not where you get one. In those cases, it is in fact more useful to have |
@claudepache Unfortunately, your two examples are actually the cases where the distinction of null/undefined is important, because the reverse operations will throw TypeError if not use correct null/undefined values.
|
@hax Yes, the distinction between null and undefined is sometimes important. My point is: it does not follow that it is useful to treat them differently when found at the LHS of the nullish-coalescing operator. |
I disagree that there are not useful use cases for distinguishing between null and undefined. I think those differences in the JavaScript world are quite important. It basically boils down to:
Just that basic premise tells me that they are actually very different at a very base level. In my personal use case, I use Google Cloud's Datastore as one of my data backends. Directly from their documentation (https://cloud.google.com/datastore/docs/concepts/queries#restrictions_on_queries):
So this is what I do for properties which I still want to query on as being "void of value". I set them as But now if I want to use the Would it not be possible to perhaps have an extra, stricter operator for the cases where matching with |
I could find many other real world examples; @lostpebble what matters are nullish coalescing common use cases. |
@lostpebble I agree that the difference between null and undefined is sometimes important, but it is not clear that the nullish-coalescing operator ought to be the specific tool to differentiate them. A concrete example of code would help to understand the usefulness. |
@lostpebble In other words, the convention you're talking about is merely that - a convention, and not a universal one. |
@ljharb you may say it is "convention" but its made more universal by the fact that:
At the very core of JavaScript, when a variable is unassigned any value - it is now One could argue deliberately defining a variable as In any case, I would need to think further about where I may run into issues with this in the future. Potentially I won't, as @claudepache said earlier:
It may be that my interactions with @Mouvedia I've never run into that specification before - but it scares me. Guess I need to be extra careful with JSON stuff. Which surprises me because isn't |
So, I've been thinking a little bit - and for the sake of giving at least one example of where something like this could cause issues:
So basically any place where we'd want to actually return that One solution would be to just continue using the current ternary operator:
Not the worst thing. But it's an example at least of where this could cause issues. Because of the dynamic nature of JavaScript, and as much as people dislike it, the difference between |
@ljharb I think the comment which you've pointed to in creating this topic kind of misses the point: tc39/ecma262#1069 (comment) For any JavaScript operation which requires accessing of properties,
This is expected behaviour because (of course) we cannot access any property of In all the examples shown on that comment, they are making use of It seems like you've used that comment to make a blanket statement that therefor the difference between the two is negligible - but it isn't really the best case at all to demonstrate that statement.
This "precedent" that we cannot access properties on either For Optional Chaining treating them the same actually still does make sense - because of the fact that accessing properties on This operator |
@lostpebble that you can construct a code example where you wouldn’t be able to use this operator doesn’t change the overarching reality that the most common use cases require treating them the same. It’s fine to simply not use this operator if it doesn’t solve your problem. The list given also gives many cases where evaluating the value treats |
@ljharb I'm going through that list and I can't see any of the examples which involve evaluation. They mostly seem to treat the input value for Could you please point out which ones evaluate so I can look deeper? I'm well aware of the most common case, and not saying that we need to ignore having this operator evaluate for "nullish" LHS values (
This seems dismissive. My position comes from a place of concern for potential future problems that people may unknowingly encounter - it's not just a personal preference. I will be well aware of whether or not I should use it. |
I agree you might apply good reasons towards differentiating them in your code; but that’s a bit strong to claim that’s the reason for their original existence. I apologize for coming off as dismissive; what i believe is that the thing that causes potential problems is differentiating |
I do get what you're saying @ljharb . And for most cases I completely agree that grouping It just worries me that there is a push in the JavaScript world to ignore the underlying reasons why these two separate states exist - and in turn trying to group them as one for the sake of simplicity. I believe there is still a place for them. Especially in equality operations - which is at the core of this specific If you don't see it as important enough to include the use case for only matching |
That already exists via ES6 default arguments, which also work with destructuring. This operator, as proposed, is what’s needed most. |
Because the nullish-coalescing operator may be thought, as the explainer of this repo says, as a mean ”to provide a default value”, some people may think hastily that it ought to be ”consistent” with defaults in function parameters and destructuring assignments. But use cases show something else. We design ”sugar” constructs in order to answer concrete needs, not ideological thoughts. As it was first designed, defaults in function parameters and in destructuring had no special behaviour for Now, concerning nullish-coalescing, experience shows that an operator is needed, that makes the distinction between ”nullish” and ”value or object of some non-nullish type”. Here, deep philosophical reason around the similarity between undefined and null is not relevant, but the fact that treating null the same way as a non-nullish value is, in most cases, unwanted, and would even make the operator plainly useless.
As I see it, in no way the design choice for defaults on the one hand and for nullish-coalescing on the other hand constitutes a judgement about the value of the distinction between different nullishes in JavaScript. In some cases, that distinction is handy. In other cases, that distinction is unwanted, not because of its intrinsic irrelevance, but simply because it is not the information we are looking for in this situation. |
I agree the differential of But as my comment before, Take your example: function takeValuesFromAnySource<T>(original: T, valueSource: any): T {
const newObject = {} as T;
for (const key in original) {
if (original.hasOwnProperty(key)) {
newObject[key] = valueSource[key] ?? original[key];
}
}
return newObject;
} I prefer |
Interesting idea, but I am not seeing |
I'd like to add my voice here with support for not treating An example: const options = { setting: null }
const setting = options.setting ?? 'default value' Explicitly providing |
I like that this is being discussed, and I hope that what the right thing is becomes clear eventually. On undefined vs null, the usual cases where I see undefined for is when I've made some kind of mistake, whereas null can be a valid default for unprovided arguments or properties (done by object destructuring, or from React, defaultProps). This is just my own usage and experience though. I don't think the operator should swallow a difference others might care about, but it seems elegant to me to behave the same for both, but return Perhaps also relevant, a brief check in Chrome's console shows that |
An illustration of that is |
Sure. But how would you use concretely the nullish-coalescing (or the undefined-coalescing, or the null-but-not-undefined-coalescing) operator with |
It means that, in your usual cases, an operator that is based on the undefined/non-undefined dichotomy would be useless (except for debugging purposes), because you would not provide undefined but by mistake. (Or am I missing something?)
What would be the semantics of such an operator? |
Sadly you cannot because older versions of IE would throw if you add an unknown property to the instance. But that's irrelevant, what I wanted to illustrate is that specification implementors do use that convention to convey that something is supported but not set: it's not just us, users. |
You didn’t understand my question, so I reformulate. We do not need to be convinced that there is an effective and useful distinction between undefined and null. We need use cases for deciding the semantics of the So, very concretely: ignoring any old browsers bugs, could you write a snippet of code that uses both |
@claudepache My usual cases, true, I wouldn't get much use out of undefined, but thinking about it more, there are some exceptions, such as objects that take different shapes, in a duck-typing style. I think I agree with those that say that this operator shouldn't be the place to differentiate between the two as far as its behavior goes. Also, for semantics, I got my GitHub project emails mixed up - I was thinking of https://github.com/TC39/proposal-optional-chaining, which currently has this discussion (tc39/proposal-optional-chaining#65) going on, which seems rather relevant. Now I'm not sure what is right. |
Ill use IE9: it has a quirk which requires the XDomainRequest onprogress handler to be a function.
If it's not clear, this example supports the current proposal. |
reading these comments i've been convinced back and forth. lol. even though i've long wanted ?? -- maybe "?" isn't the best character? what about:
there is precedent sorta with equals "==" and "===" |
@cmawhorter |
I can’t answer better than #17 (comment). |
Closing, since this proposal is at stage 4. |
tc39/ecma262#1069 (comment) demonstrates, convincingly to me, that instead of “ES6 default arguments distinguish undefined and null” setting a precedent, that they in fact defy it - and that this proposal (and optional chaining) should thus stick with the established precedent, continued in most of ES6, that null and undefined should be treated the same.
Thoughts?
The text was updated successfully, but these errors were encountered: