Proposal: allow primitives to be explicitly returned from constructors

classic Classic list List threaded Threaded
13 messages Options
Reply | Threaded
Open this post in threaded view
|

Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
Here's my proposal:

In constructors, currently, non-objects are replaced with `this`.
Here's what I think it should be replaced with:

1. When calling the constructor, if `undefined` is returned and
`new.target` is not `undefined`, return `this` instead. This is for
compatibility and ease of implementation.
1. When calling the constructor, if anything else is returned, return
that value in raw form.

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][1], 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).

[1]: https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Oriol _
This would break one of my most preferred ways to check whether a value is an object:

```js
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.

-- Oriol



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
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
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Thu, Apr 19, 2018 at 7:22 PM, Oriol _ <[hidden email]> wrote:

> This would break one of my most preferred ways to check whether a value is
> an object:
>
> ```js
> 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.
>
> -- Oriol
>
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Oriol _
> 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.

-- Oriol




_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

T.J. Crowder-2
On Fri, Apr 20, 2018 at 2:23 PM, Oriol _
> 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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Naveen Chawla
What's the use case? Maybe there's a nice way of doing what you want

On Fri, 20 Apr 2018 at 19:17 T.J. Crowder <[hidden email]> wrote:
On Fri, Apr 20, 2018 at 2:23 PM, Oriol _
> 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
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
In reply to this post by T.J. Crowder-2
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
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Fri, Apr 20, 2018 at 9:46 AM, T.J. Crowder
<[hidden email]> wrote:

> On Fri, Apr 20, 2018 at 2:23 PM, Oriol _
> <[hidden email]> 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
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
In reply to this post by Oriol _
Okay, you could invert the condition and do it this way. If it's
spec-conforming, this should work:

```js
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:

```js
var toObject = Object
function isObject(value) {
    return value === toObject(value)
}
```

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Fri, Apr 20, 2018 at 9:23 AM, Oriol _ <[hidden email]> wrote:

>> 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.
>
> -- Oriol
>
>
>
>
> _______________________________________________
> es-discuss mailing list
> [hidden email]
> https://mail.mozilla.org/listinfo/es-discuss
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Sultan
In reply to this post by Naveen Chawla
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 Fri, Apr 20, 2018 at 4:49 PM, Naveen Chawla <[hidden email]> wrote:
What's the use case? Maybe there's a nice way of doing what you want

On Fri, 20 Apr 2018 at 19:17 T.J. Crowder <[hidden email]> wrote:
On Fri, Apr 20, 2018 at 2:23 PM, Oriol _
> 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
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss



_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

T.J. Crowder-2
In reply to this post by Isiah Meadows-2
On Thu, Apr 19, 2018 at 11:49 PM, Isiah Meadows <[hidden email]> wrote:

>
> Here's my proposal:
>
> In constructors, currently, non-objects are replaced with `this`.
> Here's what I think it should be replaced with:
>
> 1. When calling the constructor, if `undefined` is returned and
> `new.target` is not `undefined`, return `this` instead. This is for
> compatibility and ease of implementation.
> 1. 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:

```js
if (condition) return someFunction();
```

instead of

```js
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:

```js
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

_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Michael Theriot
In reply to this post by Isiah Meadows-2
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.

On Thu, Apr 19, 2018 at 6:49 PM, Isiah Meadows <[hidden email]> wrote:
Here's my proposal:

In constructors, currently, non-objects are replaced with `this`.
Here's what I think it should be replaced with:

1. When calling the constructor, if `undefined` is returned and
`new.target` is not `undefined`, return `this` instead. This is for
compatibility and ease of implementation.
1. When calling the constructor, if anything else is returned, return
that value in raw form.

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][1], 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).

[1]: https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss


_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Re: Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
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:

https://www.chromestatus.com/metrics/feature/timeline/popularity/2054

-----

Isiah Meadows
[hidden email]

Looking for web consulting? Or a new website?
Send me an email and we can get started.
www.isiahmeadows.com


On Fri, Apr 20, 2018 at 7:34 PM, Michael Theriot
<[hidden email]> wrote:

> 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.
>
> On Thu, Apr 19, 2018 at 6:49 PM, Isiah Meadows <[hidden email]>
> wrote:
>>
>> Here's my proposal:
>>
>> In constructors, currently, non-objects are replaced with `this`.
>> Here's what I think it should be replaced with:
>>
>> 1. When calling the constructor, if `undefined` is returned and
>> `new.target` is not `undefined`, return `this` instead. This is for
>> compatibility and ease of implementation.
>> 1. When calling the constructor, if anything else is returned, return
>> that value in raw form.
>>
>> 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][1], 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).
>>
>> [1]:
>> https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
>>
>> -----
>>
>> Isiah Meadows
>> [hidden email]
>>
>> Looking for web consulting? Or a new website?
>> Send me an email and we can get started.
>> www.isiahmeadows.com
>> _______________________________________________
>> es-discuss mailing list
>> [hidden email]
>> https://mail.mozilla.org/listinfo/es-discuss
>
>
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss
Reply | Threaded
Open this post in threaded view
|

Fwd: Proposal: allow primitives to be explicitly returned from constructors

Isiah Meadows-2
In reply to this post by Isiah Meadows-2
Email missed the list.

-----

Isiah Meadows
[hidden email]

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 <[hidden email]>
Date: Fri, Apr 20, 2018 at 12:47 PM
Subject: Re: Proposal: allow primitives to be explicitly returned from
constructors
To: Sathya Gunasekaran <[hidden email]>


So I guess this has *no* chance of making it, then... :-(


On Fri, Apr 20, 2018, 12:18 Sathya Gunasekaran <[hidden email]> wrote:

>
> On Thu, Apr 19, 2018 at 3:49 PM, Isiah Meadows <[hidden email]> wrote:
> > Here's my proposal:
> >
> > In constructors, currently, non-objects are replaced with `this`.
> > Here's what I think it should be replaced with:
> >
> > 1. When calling the constructor, if `undefined` is returned and
> > `new.target` is not `undefined`, return `this` instead. This is for
> > compatibility and ease of implementation.
> > 1. When calling the constructor, if anything else is returned, return
> > that value in raw form.
> >
> > I know this is very *likely* very breaking, but I wonder if it would
> > be possible.
>
> I measured the usage of a non undefined return value, just for derived
> class constructors in V8
> to see if this was possible:
> https://github.com/tc39/ecma262/pull/469
>
> But even that was not web compatible:
> https://www.chromestatus.com/metrics/feature/timeline/popularity/2054
>
> > In case you're curious what this would change in the spec, it would
> > change [section 9.2.2][1], 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).
> >
> > [1]: https://tc39.github.io/ecma262/#sec-ecmascript-function-objects-construct-argumentslist-newtarget
> >
> > -----
> >
> > Isiah Meadows
> > [hidden email]
> >
> > Looking for web consulting? Or a new website?
> > Send me an email and we can get started.
> > www.isiahmeadows.com
> > _______________________________________________
> > es-discuss mailing list
> > [hidden email]
> > https://mail.mozilla.org/listinfo/es-discuss
_______________________________________________
es-discuss mailing list
[hidden email]
https://mail.mozilla.org/listinfo/es-discuss