Determining if an object can be constructed

Michał Wadas michalwadas at gmail.com
Mon Jan 23 19:26:48 UTC 2017


Actually it's possible to create pretty good heuristics to decide if it's
possible to call function as constructor, but there is no way to be sure
it's really safe.

On Mon, Jan 23, 2017 at 7:49 PM, Jordan Harband <ljharb at gmail.com> wrote:

> Unfortunately, the only practical way to know that without risking side
> effects is to read the human-produced documentation on the function, or to
> have a human read the code.
>
> On Mon, Jan 23, 2017 at 8:19 AM, Isiah Meadows <isiahmeadows at gmail.com>
> wrote:
>
>> I'll point out that all I need is some way to detect anything that is
>> callable except for classes. Basically, anything that has a `[[Call]]` that
>> doesn't throw unconditionally without entering a different scope (like
>> classes, but not %ThrowTypeError%).
>>
>> And to clarify, these would both be included per above, since it does
>> enter a different scope:
>>
>> ```js
>> // New language scope
>> function foo() {
>>   throw new TypeError()
>> }
>>
>> // New native scope (%ThrowTypeError%)
>> "use strict"
>> var foo = Object.getOwnPropertyDescriptor(
>>   arguments, "callee"
>> ).get
>> ```
>>
>> `Reflect.isConstructor` isn't sufficient for my needs, since it would
>> still consider the first `foo` above to be a constructor.
>>
>> On Sat, Jan 21, 2017, 01:14 Jordan Harband <ljharb at gmail.com> wrote:
>>
>>> The reality here is that we're all playing around what the definition of
>>> "constructor" and "callable" mean.
>>>
>>> In the spec, "constructors" are defined as having a `[[Construct]]`
>>> internal slot; something is "callable" if it has a `[[Call]]` internal
>>> slot. By that definition (https://tc39.github.io/ecma26
>>> 2/#sec-isconstructor and https://tc39.github.io/ecma262/#sec-iscallable),
>>> a `class` constructor is indeed callable (because it's defined to have
>>> `[[Call]]` throw a `TypeError`). Similarly, as defined in the spec, `typeof
>>> class Foo {}` is "function" only because it has a `[[Call]]` internal slot (
>>> https://tc39.github.io/ecma262/#table-35); if constructors lacked a
>>> `[[Call]]` slot (such that `IsConstructor` returned `true` for them), then
>>> `typeof someConstructor` would return "object".
>>>
>>> Obviously the committee could have chosen to define these things
>>> differently; but this is how things are defined.
>>>
>>>
>>>
>>> I'm going to claim that conceptually - eg, to the majority of users -
>>> something is a constructor when it's *intended* to be used with `new`. In
>>> other words, "what it returns" isn't actually the point - if you're "meant"
>>> to use it with `new`, it's a constructor, otherwise, it's a function - and
>>> functions that work with both can be thought of as a dual
>>> constructor/factory (the factory calls the constructor for you). However,
>>> that conceptual definition is not one that can be programmatically
>>> determined, because "programmer intention" in this regard simply isn't
>>> inherently enshrined in an observable way, whether choosing `class` or
>>> `function`.
>>>
>>> Personally I think it would be wonderful to expose `IsConstructor`
>>> (`IsCallable` is already exposed via `typeof` returning "function"), but I
>>> feel quite confident that neither actually address any of the use cases in
>>> this thread.
>>>
>>> In addition, "safe to call" or "safe to use with `new`" all depends on
>>> your definition of "safe", and it's clear from this thread that that does
>>> not have a universally agreed-upon definition either.
>>>
>>> It might be useful to distill things down to 1) concrete use cases for
>>> calling or instantiating a function where you don't already know what it
>>> does, and can't assert in your human documentation what you expect; 2) a
>>> definition of "constructor", either a different one if you don't agree with
>>> mine above, or if you do, a form of mine that can be programmatically
>>> determined, and 3) a definition of "safe" which means more than "doesn't
>>> throw an exception".
>>>
>>> On Fri, Jan 20, 2017 at 6:52 PM, Scott Sauyet <scott at sauyet.com> wrote:
>>>
>>> Bradley Meck wrote:
>>> >> 1. every call to `new Foo(...args)` creates a distinct object not
>>> >> reference-equal to any other such call.
>>> >
>>> > Would this mean
>>> >
>>> > ```
>>> > function factory() { return []; }
>>> > ```
>>> >
>>> > would qualify as a constructor?
>>>
>>> I'm thinking of that as a necessary, but not a sufficient condition.
>>>
>>> If it fails that test it cannot be a constructor.  It's clear that
>>> there are other tests.  It's not clear to me what they are.
>>>
>>>   -- Scott
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>>
>>> _______________________________________________
>>> es-discuss mailing list
>>> es-discuss at mozilla.org
>>> https://mail.mozilla.org/listinfo/es-discuss
>>>
>>
>
> _______________________________________________
> es-discuss mailing list
> es-discuss at mozilla.org
> https://mail.mozilla.org/listinfo/es-discuss
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20170123/09c479fe/attachment.html>


More information about the es-discuss mailing list