Proposal: allow primitives to be explicitly returned from constructors
This would break one of my most preferred ways to check whether a value is an object:
function isObject(value) {
return value === new function(){ return value };
}
Unlike Object(value) === value
, the above is just syntactic, it does not require Object
to be the built-in one.
And I don't really see the point, constructors are supposed to construct objects. If you want primitives, you can always use function calls.
You already can't assume the result is typeof new function () { return value } === "object"
for every value
- you can return
functions out of them. Also, you could migrate that to avoid creating
any temporary objects at all - here's what I usually do:
function isObject(value) {
return value != null && (
typeof value === "object" ||
typeof value === "function"
)
}
But my idea was just to bring new
and normal calls a little closer
to one another. Eventually, I'd like to see if primitive wrapper types
could disappear, and this is one of the areas where I'm trying to see
if it's feasible to do in JS. (Wrapper types are actually a
complicating factor in JS optimization and the object model in
general.)
But of course, this could all break the web, and if you have no choice in the matter (say, legacy code base with way too many instances of it), it would be too breaking to even be worth doing this.
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
You already can't assume the result is
typeof new function () { return value } === "object"
Yes, that's why I need reliable ways to test whether a value is an object, and your proposal breaks one of these.
here's what I usually do:
function isObject(value) { return value != null && ( typeof value === "object" || typeof value === "function" ) }
No, typeof
is not reliable, because it's implementation-defined for non-standard non-callable exotic objects.
For example, old IE used to return "unknown"
in various cases.
On Fri, Apr 20, 2018 at 2:23 PM, Oriol _ <oriol-bugzilla at hotmail.com> wrote:
No,
typeof
is not reliable, because it's implementation-defined for non-standard non-callable exotic objects.For example, old IE used to return
"unknown"
in various cases.
Also "object"
for host-provided functions (such as
document.createElement
); IE8 still does that. (Thankfully IE11 doesn't.)
(I suppose that would have passed Isiah's isObject
test anyway, but the
point is that typeof
is, sadly, a weak reed...)
-- T.J. Crowder
What's the use case? Maybe there's a nice way of doing what you want
I normally name it isReferenceType
or similar, but was just reusing
the name originally used here. For the purposes of this, my
isReferenceType
is equivalent to the value === new function () { return value }
check, while still avoiding diving into builtins. I
was just focused on a correct equivalent.
I know typeof
can be rather loose at times with old IE (and heck, it
once was in other engines, too - consider the old V8 bug typeof /foo/ === "function"
).
My question was whether it was feasible now, and specifically with
respect to non-primitives (where isReferenceType(value) === false
).
So far, the only problem explained here was with a fairly unique use
case I offered an alternative of, and I'm just trying to explore to
see if the breaking nature has changed enough it's worthy to consider
lifting the restriction.
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
Okay, you could invert the condition and do it this way. If it's spec-conforming, this should work:
function isObject(value) {
return value != null &&
typeof value !== "boolean" &&
typeof value !== "number" &&
typeof value !== "string" &&
typeof value !== "symbol"
}
Alternative, if you're okay with builtins (and this is what I initially had before I sent the original message), you could do this:
var toObject = Object
function isObject(value) {
return value === toObject(value)
}
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
One of the use case for this is – given a function that is either one that returns an instance or one that returns an explicit return value, but would otherwise throw if invoked without the "new" keyword.
Always being able to safely invoke it with "new" is a nice guarantee to have that wouldn't require you to explicitly know before hand whether a function is a constructor or function.
Now since this does not reflect well on the variants that return primitives it means you cannot currently always use "new".
Broadly put this could touch on every use case thats involves the need to know whether a function is a constructor or not before you decide to call it with "new" or not because not calling it with "new" might throw an error.
On Thu, Apr 19, 2018 at 11:49 PM, Isiah Meadows <isiahmeadows at gmail.com>
wrote:
Here's my proposal:
In constructors, currently, non-objects are replaced with
this
. Here's what I think it should be replaced with:
- When calling the constructor, if
undefined
is returned andnew.target
is notundefined
, returnthis
instead. This is for compatibility and ease of implementation.- When calling the constructor, if anything else is returned, return that value in raw form.
I think you'll struggle to demonstrate that this is web-safe; certainly doing so would be a major undertaking.
One particular habit that would be of concern is people writing:
if (condition) return someFunction();
instead of
if (condition) {
someFunction();
return;
}
...when they know full well that they don't actually want to return the
result of someFunction
. Mostly I see that in Node-style callbacks where
the return value is ignored, but it wouldn't surprise me at all if there
was code in the wild that did that in a constructor, happily (and probably
unintentaionally) taking advantage of the fact that the return value will
be ignored.
Horribly contrived example:
class Multiplier {
constructor(a, b) {
if (typeof a === "undefined") {
this.setA(7);
return this.setB(6);
}
this.setA(a);
this.setB(b);
}
setA(value) {
return this.a = value;
}
setB(value) {
return this.b = value;
}
execute() {
return this.a * this.b;
}
}
const m = new Multiplier();
console.log(m.execute());
And just generally, changing a behavior that's so well-established without some kind of mode (and I'm told There Will Be No More Modes) seems like asking for trouble. Would need to have a massive, unambiguous benefit.
-- T.J. Crowder
I don't understand the use case. If anything I would like it if returning
an object that fails new Class instanceof Class
to also fail, not permit
even more oddities.
My rationale was detailed in a response to another person eariler:
But my idea was just to bring
new
and normal calls a little closer
to one another. Eventually, I'd like to see if primitive wrapper types could disappear, and this is one of the areas where I'm trying to see if it's feasible to do in JS. (Wrapper types are actually a complicating factor in JS optimization and the object model in general.)
From a reply that (I presume accidentally) missed the list, It doesn't
appear to be web-compatible, so this entire discussion would qualify as moot:
www.chromestatus.com/metrics/feature/timeline/popularity/2054
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
Email missed the list.
Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com
---------- Forwarded message ---------- From: Isiah Meadows <isiahmeadows at gmail.com>
Date: Fri, Apr 20, 2018 at 12:47 PM Subject: Re: Proposal: allow primitives to be explicitly returned from constructors To: Sathya Gunasekaran <gsathya at chromium.org>
So I guess this has no chance of making it, then... :-(
Here's my proposal:
In constructors, currently, non-objects are replaced with
this
. Here's what I think it should be replaced with:undefined
is returned andnew.target
is notundefined
, returnthis
instead. This is for compatibility and ease of implementation.I know this is very likely very breaking, but I wonder if it would be possible.
In case you're curious what this would change in the spec, it would change section 9.2.2, step 13.a-13.c to this:
a. If result.[[Value]] is not
undefined
, return NormalCompletion(result.[[Value]]
). b. If kind is"base"
, return NormalCompletion(thisArgument).Isiah Meadows me at isiahmeadows.com
Looking for web consulting? Or a new website? Send me an email and we can get started. www.isiahmeadows.com