Optional : in ?: operator [was: Existential operator]
On Apr 13, 2011, at 10:46 PM, Kyle Simpson wrote:
I'm not sure I see how this is really introducing an additional ambiguity?
It is obviously introducing an ambiguity where none exists today. ?: is indivisible, unlike if vs. if else.
I was referring to no additional visual ambiguity inside the ?: with respect to operator precedence and how to interpret a chain of nested ?:, as compared to doing the same task if
:
is optional.a ? b ? c : d ? e ? f : g : h ? i : j : k ==> a ? (b ? c : (d ? (e ? f : g) : (h ? i : j))) : k
Firstly, that code has no real ambiguity, because operator precedence tells us how those implied () sets disambiguate it.
In an LR(1) grammar, if vs. if-else or ? vs. ?: is a shift-reduce conflict (to use yacc terms). It is an ambiguity. It can be disambiguated, but please do not confuse disambiguation via shifting with "no real ambiguity".
Secondly, in my opinion, the visual "ambiguity" of it is not made any more burdensome (and is even perhaps SLIGHTLY clearer) by adding () sets to disambiguate where you want optional
:
, such as this example (same as above, but whereg
andj
are omitted as placeholders for impliedundefined
):a ? b ? c : d ? (e ? f) : (h ? i) : k ==> a ? (b ? c : (d ? (e ? f : undefined) : (h ? i : undefined))) : k
This is all akin to bracing "then" and "else" clauses, and there's no need to belabor it. My point that we should not add more of the same ambiguity stands.
In sum, this sounds like an argument against ? as infix operator (implied : undefined).
I'm sorry, I'm lost by this statement. I don't understand on what basis you conclude that I just argued against the very thing I'm asking for. Can you elaborate at all?
You made an ad-hoc argument for a ? b : undefined but want to write that as a ? b. The latter is not obviously the same (Dmitry pointed out the potential for confusion with ??, which has a very different result). It's also not obviously a good non-hard case to burn into the grammar.
var opts = { doX: (someX > 0 && someX < 10) ? someX , // leaving off the
: undefined
(or: null
if you prefer) doY: (someY > 0 && someY < 1) ? someY // ditto };Sorry, I think this is a hazardous pattern. "doX" suggests a boolean value,
How is
doX = (someX > 0 && someX < 10) ? someX
more suggestive of a "boolean" value than is
doX = (someX > 0 && someX < 10) ? someX : undefined
The name "doX" connotes boolean.
but you want (number | undefined), a type union.
I'm not sure if you're arguing against: a) the pattern of having an
undefined
value in a variable when "unset", that otherwise stores numbers when it's "set"; OR b) the implied: undefined
Both, (b) because of (a). I was explicit about this, there's no confusion.
If (a), this was a long held pattern long before I ever wrote my first line of JavaScript. Moreover, it's far more common today on the greater web than any code I've ever written. I'd argue it's pretty close to a de facto pattern at this point, so I'm not sure what the point is in using that argument to contradict my request for an implied
: undefined
. Moreover, this code sample I gave is only one such example. If it irks you that much, I'm sure I could find other examples to illustrate. But, I'm not really sure how that helps or hinders the process.
No, people do not risk converting undefined to NaN (to 0). It's true that var hoisting means undefined inhabits the type of all vars, but unless yo use an uninitialized var, that's not an issue.
If any consumer fails to discriminate using typeof, they'll get undefined which coerces to NaN as number (to 0 as integer). Bad times.
First of all, I'm talking about code where I am the consumer, so I take care to make sure the proper checks are done.
Why don't you set doX (or just x) to the minimized value you want?
Secondly, criticizing the pattern as a substitute for criticizing the idea/proposal is a non sequitur, or orthogonal at best.
A hazardous pattern is no argument for syntactic sugar. At best you have a minority use-case. At worst, it's a latent bug. Why should we add amgiguous sugar for this?
I don't think this feature is worth all this discussion or time, which is why I haven't said very much. But I don't like the idea.
It is ambiguous, in the sense that if you wrote the grammar in the natural way it would be an ambiguous grammar, so you have to rewrite the grammar in such a way as to force precedence rules to disambiguate.
But more importantly, I don't believe it's an important enough case to be worth syntactic support for, especially since `undefined' isn't always the default value you want to use.
And FWIW: Racket actually moved away from supporting one-armed if' -- they disabled it somewhere around v4, I think -- because experience showed that the cases where it was useful were outnumbered by the cases where it caused accidental leakage of
undefined' values, which is the moral equivalent of a NullPointerException.
In an LR(1) grammar, if vs. if-else or ? vs. ?: is a shift-reduce conflict (to use yacc terms). It is an ambiguity. It can be disambiguated, but please do not confuse disambiguation via shifting with "no real ambiguity".
My point is it IS disambiguated by the definition of operator precedence. The adding of an optional nature to the : portion of ?: wouldn't change that, as the expression would still hinge on the same definition of operator precedence. So it doesn't really introduce additional ambiguity (either visual or processing-wise), that isn't already there for ?: usage. It just piggybacks on that same operator-precedence-disambiguity which is long-held in JavaScript. In fact, based on the definition I'm putting forth, I don't think it requires any (or hardly any) additional "rules" for operator precedence or disambiguation.
I'm sorry, I'm lost by this statement. I don't understand on what basis you conclude that I just argued against the very thing I'm asking for. Can you elaborate at all?
You made an ad-hoc argument for a ? b : undefined but want to write that as a ? b. The latter is not obviously the same (Dmitry pointed out the potential for confusion with ??, which has a very different result).
OK, fair enough, I can see how some confusion is possible, IF the ?? operator is also added. But I am not convinced that possible future confusion is, alone, enough for invalidation of an idea. I can name a number of things coming down the pike for ES next's that are, at first, a little confusing, and take some getting used to. Their value to the language, and to syntactic sugaring, withstands the initial confusion.
It's also not obviously a good non-hard case to burn into the grammar.
What is non-hard about saying that, in the processing of any ?: expression,
if the ? is present but the : is not found where it is expected, then the :
is implied and is always : undefined
(or : void 0
, if you prefer)?
Perhaps I'm missing it, but I really don't see how it's any harder than that
alone.
How is
doX = (someX > 0 && someX < 10) ? someX
more suggestive of a "boolean" value than is
doX = (someX > 0 && someX < 10) ? someX : undefined
The name "doX" connotes boolean.
OK, so your complaint is about the bad name I gave that variable. Fine. Agreed. "do" was a bad word for a non-boolean. s/do(X|Y)/coord$1. Variables names in examples aside, the point of the example (the operator usage) should be clear. Not sure why it isn't?
I'm not sure if you're arguing against: a) the pattern of having an
undefined
value in a variable when "unset", that otherwise stores numbers when it's "set"; OR b) the implied: undefined
Both, (b) because of (a). I was explicit about this, there's no confusion.
There is still confusion on my part, because I honestly don't see how (b) necessarily and unequivocally follows from (a). I can clearly see that you want to connect them, but I don't see why they have to be. (see below).
No, people do not risk converting undefined to NaN (to 0). It's true that var hoisting means undefined inhabits the type of all vars, but unless yo use an uninitialized var, that's not an issue.
There's many other ways that variables get to undefined
besides them not
yet being initialized. For instance:
delete opts.coordX
- unsetting variables so the value is GC'd.
- setting variables to
undefined
(orvoid 0
) to prevent a memory leak, for instance on theonreadystatechange
andonload
handlers of XHR objects, in IE. - etc
The pattern of explicitly assigning undefined
to a variable that otherwise
holds some real value, and then making logic decisions based on if the
variable is in a "defined" or "undefined" state, is clear, works, and is
well known (if distasteful to some, including obviously you). I'm surprised
you're insisting that it's purely niche (it's not, I can find lots of
examples, even in major js libs) or it's bad/wrong (just because you say
so?).
But, whether it's right or wrong, it's clearly possible in the language, and even if you dislike it, used by a lot of developers besides myself, making it (at least a candidate for) a de facto coding pattern.
First of all, I'm talking about code where I am the consumer, so I take care to make sure the proper checks are done.
Why don't you set doX (or just x) to the minimized value you want?
Encapsulation. Inside a class, method, module, etc, you define the base default values for the configuration params. Then the outside user of the API simply passes or doesn't pass what they want in, and the configuration mixes in what they pass with what the defaults are. This is a hugely standard pattern across tons of different public libs, including major ones like jQuery UI, etc.
So, from the outside, simply not passing in a coordX
property on the
opts
config object is the most common pattern, and in general, preferable.
But, as I showed, when defining the config object using the object literal
syntax, there's no way to conditionally not add a property to the object
(you have to do that outside the object literal, in a per-statement
fashion). So, it's nice to have a way to define a property, but set its
value to undefined
, which (relying on proper type checking/coercion-safety
inside the function) behaves exactly the same as not passing it in at all.
A hazardous pattern is no argument for syntactic sugar. At best you have a minority use-case. At worst, it's a latent bug.
Are you suggesting that the ability to assign undefined
to a variable or
property is so bad that it's actually a bug in the language?
Why should we add amgiguous [sic] sugar for this?
Why ever add any syntactic sugar? Whatever reason there ever is for adding syntactic sugar, that same reason applies here. Save typing. Make code cleaner because there's less of it. Etc etc.
At least in the case of defining an object using object literal syntax,
being able to conditionally assign undefined
to a key (as a near
substitute for not setting the property in the first place) is helpful.
Without the sugar, there's still plenty of JavaScript coders who are going
to keep doing as I do, which is responsibly (that is, with safe type checks)
use the undefined
value as a way to explicitly put a variable (back) into
an "unset" state, and then later make logic decisions based on if a variable
is in the "set" state or not. We'll all just keep typing the redundant : undefined
. And life will be fine.
But I'll also keep wishing that JavaScript had some syntactic sugar like
CoffeeScript has. CS has the pattern (as shown originally in the thread)
where the : undefined
is omitted/implied with that ?. operator. I would
think that's a valid support for why it's at least reasonable to consider
this syntactic sugar for JavaScript.
Brendan, you've asked for other coding examples where I use the pattern of
some variable being undefined
or not to trigger different behavior (that
is, to use the variable or not). Here's two more:
- I have a templating engine DSL (called HandlebarJS) I wrote (in JS), which includes a very strict minimal subset of a "JavaScript-like" syntax for declaring template variables in the definition-header of a template section. In fact, the variable declaration stuff is massaged just slightly (for variable namespacing, mostly), and then executed as straight JavaScript.
In a template section header, I'm able to define a "local variable" for the
section which has the ID reference of another sub-template section to
include. If you ask to include a sub-template, and the "local variable" you
give as the name of the template to include is an empty "" or is undefined
or otherwise falsy, then the templating engine simply skips over that
template section inclusion. Example:
{$: "#main" | content = data.content ? "#content" : "" $} <h1>Hello World</h1> {$= @content $} {$}
{$: "#content"} <p> {$= data.content $} </p> {$}
So, if the data.content
variable is truthy, then the local variable
content
gets value "#content" (a string ID reference to the sub-template
section of that name), and if not, then it ends up as the empty string "".
Then, after the <h1> tag, a template-include is called, with {$= @content
$}, which basically says, get the value out of that local variable, and if
it's a reference (by ID) to a template section, then include it. If the
variable referenced is empty, or undefined, or null, or whatever falsy, then
simply silently don't include anything.
Of course, the : ""
part of the variable declaration is what's relevant to
our discussion. I could obviously specify another template ID in that
string... but in this example I'm giving, if the data.content
is empty, I
don't want to include the markup (the <p>...</p>) from the #content template
at all, so I just set the local variable to "", which results in no sub-template being included.
Here's where this gets to the point: in my template DSL, you're allowed to
drop the : ""
from ?: usage, so the declaration for main can look like
slightly cleaner, like this:
{$: "#main" | content = data.content ? "#content" $}
Purely syntax sugar I'm giving there, to help the template not have so much
"code" in it. If the "" or undefined
or whatever falsy value in the "or"
case can be assumed, it makes the writing of that variable declaration a
little bit nicer. When I parse the data declarations from my template
syntax, and then hand it off to JavaScript, I simply substitute in the : undefined
if it's not present. I even take care of nested ?: with the
optional :
parts.
To put a finer point on it, it would be nicer/easier if I didn't have to add those implied clauses in, because the JavaScript language just supported that syntactic sugar directly.
- I've got cases where I have a set of code in an embeddable widget, that someone can take the code and embed into their site. My code relies on jQuery, but at least jQuery 1.4. So, I first check to see if jQuery is already present, and if it's 1.4+, and then if so, I just use the page's copy of jQuery. Otherwise, I go ahead and load jQuery dynamically for my code to use.
So, a drastically simplified version (yes, I know the version matching logic is faulty from the over-simplification) of this code looks like this:
(function(){ var jq = ($ && $.fn.jquery.match(/^1.[4-9]/)) ? $ : undefined;
...
if (typeof jq == "undefined") { // go ahead and load jQuery dynamically } })();
So, how can I write this code differently? Of course there's other ways to write it.
var jq;
($ && $.fn.jquery.match(/^1.[4-9]/)) && jq = $; // jq is either jQuery or
it's still undefined
, which I prefer
OR
var jq = ($ && $.fn.jquery.match(/^1.[4-9]/)) ? $ : null; // jq is either
jQuery or it's null
, which I like less
OR
var jq = ($ && $.fn.jquery.match(/^1.[4-9]/)) && $; // jq is either jQuery
or it's false
, which I like less
OR .......
And there's probably half a dozen other patterns too. I could use null
as
the sentinel value, I could use false
, heck I could even use an empty ""
string.
The point is, I prefer to use undefined
in such cases, because
semantically, I'm saying that my jq
is in fact "undefined" (or rather,
"not yet defined") if either jQuery is not present, or the version match
fails. I don't prefer to use false
or null
or 0
or ""
as the
alternate value, I prefer to use undefined
.
And so, it'd be nice if my var
statement could be simpler, like:
var jq = ($ && $.fn.jquery.match(/^1.[4-9]/)) ? $;
Why? because it keeps the declaration and initialization all in one
statement, which is cleaner, and because it preserves that jq
is only ever
a valid reference to jQuery, or it's strictly undefined
... there's no
other values I have to worry about it being. That also means that the check
later is typeof jq == "undefined"
, which I consider to be most semantic,
rather than typeof jq != "object"
(which fails if I use null
) or jq != null
(which works for either null
or undefined
, but in my opinion is
less semantic).
In any case, set the doX
argument from earlier aside, and there's still
other examples of how I like to use the semantic meaning of undefined
for
signaling that a variable is not yet initialized, and that the code needs to
react accordingly if so. You may disagree entirely with both above usages as
well, but the point is that it's not some limited one-off niche use case,
it's a pattern that I find useful across a variety of projects, and one
which I wish had just a tiny bit more semantic sugar to it.
On Apr 14, 2011, at 12:00 AM, Kyle Simpson wrote:
It's also not obviously a good non-hard case to burn into the grammar.
What is non-hard about saying that, in the processing of any ?: expression, if the ? is present but the : is not found where it is expected, then the : is implied and is always
: undefined
(or: void 0
, if you prefer)? Perhaps I'm missing it, but I really don't see how it's any harder than that alone.
Please read en.wikipedia.org/wiki/Hard_cases_make_bad_law -- I think you are misreading "hard" in "hard case".
The name "doX" connotes boolean.
OK, so your complaint is about the bad name I gave that variable. Fine. Agreed. "do" was a bad word for a non-boolean. s/do(X|Y)/coord$1. Variables names in examples aside, the point of the example (the operator usage) should be clear. Not sure why it isn't?
I wasn't picking on the name in isolation. It was pretty clearly influenced by the type it holds being a union of undefined with number, which is the underlying bone of contention. That is not merely a matter of naming.
[snip way too much, to avoid endless fisking and counter-fisking]
A hazardous pattern is no argument for syntactic sugar. At best you have a minority use-case. At worst, it's a latent bug.
Are you suggesting that the ability to assign
undefined
to a variable or property is so bad that it's actually a bug in the language?
The same problem applies with any bottom type in a dynamic language.
I do think hoisting of var is a bug in the language because it enables what looks like use-before-set errors and makes for more undefined inhabitation of vars that would otherwise by monotyped and in smaller scopes, but that is water under the bridge by almost 16 years.
What is not water under the bridge is burning syntax and adding another dangling-else form on this peculiar case, which has only come up now and still seems like a very obscure case, never mind CoffeeScript (where it may be even more obscure, even though served -- again, CS lacks the ?: operator so it can be different, we can't just harvest bits of syntax without careful validation, etc. etc.).
Encoding undefined into an expression as an implicit result, only to be stored in a variable so you can treat that variable as if it were never set? It looks like a hard case to me. More, it looks like a hard case with type confusion risk.
Even if you manage to avoid undefined-as-number bugs, having to write ": undefined" or similar out the long way, if you truly can't use &&, is better on balance than making : optional after ? in the core language we all have to spec, implement, teach, and share.
On 14.04.2011 1:23, David Herman wrote:
I don't think this feature is worth all this discussion or time, which is why I haven't said very much. But I don't like the idea.
Are you talking about Kyles proposal or about my initial?
I remind, my initial proposal was exactly about "?." operator to avoid this noisy and completely useless:
if (foo.bar) { if (foo.bar.baz) { if (typeof foo.bar.baz.quax == "function") { foo.bar.baz.quax("value") } } }
and to replace it with:
foo.bar?.baz?.quax("value");
we can adopt it only for property accessor, nor for a variable binding directly (which seems doesn't create ambiguity). I.e. only for:
foo?.bar
but not for:
foo?
Dmitry.
On 14.04.2011 18:32, Dmitry A. Soshnikov wrote:
On 14.04.2011 1:23, David Herman wrote:
I don't think this feature is worth all this discussion or time, which is why I haven't said very much. But I don't like the idea.
Are you talking about Kyles proposal or about my initial?
I remind, my initial proposal was exactly about "?." operator to avoid this noisy and completely useless:
if (foo.bar) { if (foo.bar.baz) { if (typeof foo.bar.baz.quax == "function") { foo.bar.baz.quax("value") } } }
and to replace it with:
foo.bar?.baz?.quax("value");
Sorry, with foo.bar?.baz?.quax?("value")
which requires to parse not only "?." for functions as you see. Though, if it won't go for all convenient cases such as simple foo? then probably it's not so important.
foo? ? bar : baz // looks odd, but acceptable though
Dmitry.
On 11:59 AM, Kyle Simpson wrote:
Brendan, you've asked for other coding examples where I use the pattern of some variable being
undefined
or not to trigger different behavior (that is, to use the variable or not). Here's two more:
Here are some examples from Firebug code:
Lazy object construction. A pervasive pattern in our code.
if (!context.eventsMonitored)
context.eventsMonitored = [];
Temp introduced because undefined
come at depth:
var htmlPanel = context.getPanel("html", true);
var vars = htmlPanel ? htmlPanel.getInspectorVars() : null;
Another undefined
at depth
(state ? state.wasScrolledToBottom : "no prev state")
jjb
On Apr 14, 2011, at 5:03 PM, John J. Barton wrote:
On 11:59 AM, Kyle Simpson wrote:
Brendan, you've asked for other coding examples where I use the pattern of some variable being
undefined
or not to trigger different behavior (that is, to use the variable or not). Here's two more:Here are some examples from Firebug code:
Lazy object construction. A pervasive pattern in our code.
if (!context.eventsMonitored) context.eventsMonitored = [];
This example does not argue strongly for infix-? given how JS users already write if-then (no else) or use || and &&, e.g.
!context.eventsMonitored && (context.eventsMonitored = []);
context.eventsMonitored || (context.eventsMonitored = []);
Temp introduced because
undefined
come at depth: var htmlPanel = context.getPanel("html", true); var vars = htmlPanel ? htmlPanel.getInspectorVars() : null;
Why wouldn't you use && here?
Another
undefined
at depth (state ? state.wasScrolledToBottom : "no prev state")
This is explicltly ?:, i.e., if-the-else. It can't be simplified to if-then. Did you mean something else?
Kyle's proposal.
On 4/14/2011 8:17 AM, Brendan Eich wrote:
On Apr 14, 2011, at 5:03 PM, John J. Barton wrote:
On 11:59 AM, Kyle Simpson wrote:
Brendan, you've asked for other coding examples where I use the pattern of some variable being
undefined
or not to trigger different behavior (that is, to use the variable or not). Here's two more: Here are some examples from Firebug code:Lazy object construction. A pervasive pattern in our code.
if (!context.eventsMonitored) context.eventsMonitored = [];
This example does not argue strongly for infix-? given how JS users already write if-then (no else) or use || and&&, e.g.
!context.eventsMonitored&& (context.eventsMonitored = []); context.eventsMonitored || (context.eventsMonitored = []);
I guess the typical form is context.eventsMonitored = context.eventsMonitored || [];
I'm not arguing "for" anything, only pointing out cases where undefined tests, which are pervasive in JS, require repeating extra repeating code.
Temp introduced because
undefined
come at depth: var htmlPanel = context.getPanel("html", true); var vars = htmlPanel ? htmlPanel.getInspectorVars() : null; Why wouldn't you use&& here?
Sorry I don't understand the question. What the code wants to express is "if context.getPanel('html', true) is undefined, set vars to null, otherwise set it to context.getPanel('html', true).getInspectorVars()".
Perhaps there is no better solution, but often I find that I want to say "call this chain of functions and use the bottom value, but if any of them return undefined, then just be undefined, don't get all pissed off and throw an exception. Being undefined is how JavaScript is." I was imagining that this was the feature being discussed.
jjb
On Apr 14, 2011, at 5:55 PM, John J. Barton wrote:
I guess the typical form is context.eventsMonitored = context.eventsMonitored || [];
JS hackers don't like assigning over top of the same value, so I find the parenthesized assignment on the right of || more common.
I'm not arguing "for" anything, only pointing out cases where undefined tests, which are pervasive in JS, require repeating extra repeating code.
Ok. It's good to have clarity over proposals. The infix-? idea Kyle put forth was what you seemed to be following up with examples of your own. Indeed, infix-? helps avoid parentheses:
!context.eventsMonitored ? context.eventsMonitored = [];
vs.
context.eventsMonitored || (context.eventsMonitored = []);
But that is all it does (net two chars saved above, thanks to loss of ! via || instead of &&), and it adds a dangling-else form.
Temp introduced because
undefined
come at depth: var htmlPanel = context.getPanel("html", true); var vars = htmlPanel ? htmlPanel.getInspectorVars() : null; Why wouldn't you use&& here? Sorry I don't understand the question. What the code wants to express is "if context.getPanel('html', true) is undefined
"is undefined" -> "is falsy". Does context.getPanel return null or undefined in the not-found case?
, set vars to null, otherwise set it to context.getPanel('html', true).getInspectorVars()".
If null or undefined will do, then my question was why not write this:
var htmlPanel = context.getPanel("html", true); var vars = htmlPanel && htmlPanel.getInspectorVars();
Here is where Dmitry's proposal of ?. as a new operator, based on the same one from CoffeeScript, can win:
var vars = context.getPanel("html", true)?.getInspectorVars();
Not the topic of the message you followed up directly (which was infix-?), but no worries.
Perhaps there is no better solution, but often I find that I want to say "call this chain of functions and use the bottom value, but if any of them return undefined, then just be undefined, don't get all pissed off and throw an exception. Being undefined is how JavaScript is." I was imagining that this was the feature being discussed.
No imagination required -- this is clearly the CoffeeScript ?. operator Dmitry brought up. It has its uses. We should get back to a message whose subject is explicitly about ?. ("Existential operator") and discuss it more.
I was referring to no additional visual ambiguity inside the ?: with respect to operator precedence and how to interpret a chain of nested ?:, as compared to doing the same task if
:
is optional.a ? b ? c : d ? e ? f : g : h ? i : j : k ==>
a ? (b ? c : (d ? (e ? f : g) : (h ? i : j))) : k
Firstly, that code has no real ambiguity, because operator precedence tells us how those implied () sets disambiguate it.
Secondly, in my opinion, the visual "ambiguity" of it is not made any more burdensome (and is even perhaps SLIGHTLY clearer) by adding () sets to disambiguate where you want optional
:
, such as this example (same as above, but whereg
andj
are omitted as placeholders for impliedundefined
):a ? b ? c : d ? (e ? f) : (h ? i) : k ==>
a ? (b ? c : (d ? (e ? f : undefined) : (h ? i : undefined))) : k
Moreover, this code wouldn't have any actual ambiguity even if you omitted those two sets of () in the original. It would still be a valid expression, with a different (but still unambiguous) interpretation:
a ? b ? c : d ? e ? f : h ? i : k ==>
a ? (b ? c : (d ? (e ? f : (h ? i : k)) : undefined)) : undefined
Developers who chain/nest ?: together are already familiar with how and when they have to use () to disambiguate, and the rules for what happens when they don't, and it seems like exactly the same effort for them to do so if implied
: undefined
were something they wanted to/could leverage.I'm sorry, I'm lost by this statement. I don't understand on what basis you conclude that I just argued against the very thing I'm asking for. Can you elaborate at all?
How is
doX = (someX > 0 && someX < 10) ? someX
more suggestive of a "boolean" value than is
doX = (someX > 0 && someX < 10) ? someX : undefined
Or, put another way, how are either of them suggestive of a boolean value result? Unless you mean simply the name "doX" being suggestive of "do" or "do not" (probably a poor name choice for my example), I don't see how either code snippet itself implies a boolean value result.
As far as I am concerned, they both clearly indicate selecting a value (type irrelevant) based on a boolean test. The implied part hides one of the variable choices, yes, but I don't see how that suggests an entirely different type of operation/result?
I'm not sure if you're arguing against: a) the pattern of having an
undefined
value in a variable when "unset", that otherwise stores numbers when it's "set"; OR b) the implied: undefined
If (a), this was a long held pattern long before I ever wrote my first line of JavaScript. Moreover, it's far more common today on the greater web than any code I've ever written. I'd argue it's pretty close to a de facto pattern at this point, so I'm not sure what the point is in using that argument to contradict my request for an implied
: undefined
. Moreover, this code sample I gave is only one such example. If it irks you that much, I'm sure I could find other examples to illustrate. But, I'm not really sure how that helps or hinders the process.If (b), I'm not sure what the type union for "set" vs. "unset" has to do with the request for implied
: undefined
? These seem like different discussions altogether.It sounds like you're basically saying either that my idea is very niche and thus irrelevant to consider, or that the supporting reasoning behind the idea is flawed/bad code, and thus the idea is necessarily flawed/bad. Is it either, both, or neither of those that you are suggesting?
First of all, I'm talking about code where I am the consumer, so I take care to make sure the proper checks are done.
Secondly, criticizing the pattern as a substitute for criticizing the idea/proposal is a non sequitur, or orthogonal at best. Completely ignoring the implied
: undefined
for a moment, there's plenty of other ways that a variable might end up with a proper (numeric) value in the "set" state, and anundefined
value in the "unset" state. It is therefore a granted that, regardless of whether implied: undefined
were ever to be considered valid or not, safely checking variables with proper understanding of type coercion is a must.