constructor, super, and data members issue

Ranando King kingmph at gmail.com
Mon Sep 3 22:44:07 UTC 2018


That scenario is intentional. I see no need to ban it. I would only want to
ban the confusing case of direct assignment in the outer class declaration.
For cases where the user intentionally defines a class as you have done,
they should know that what they've done will create a class that is
persistently re-defined with each instance. As has been said many times
before, it's good to reduce the number of foot-guns, but at some point, you
have to expect some level of responsibility from the programmer. Consider
that rule as little more than a safety switch.

On Mon, Sep 3, 2018 at 3:52 PM Jordan Harband <ljharb at gmail.com> wrote:

> `field = (function () { return class { }; }())` - how exactly would you
> propose banning creating a class inside class fields?
>
> On Mon, Sep 3, 2018 at 12:05 PM, Ranando King <kingmph at gmail.com> wrote:
>
>> I've been thinking about the problems around this some more. At first I
>> couldn't get past the dissenting arguments from issue #123, but I've since
>> come up with a solution that might work. What if:
>>
>> * Make it illegal to define a class directly on a class field in a class
>> declaration.
>> * Move the assignment portion of a class field declaration into a getter
>> on the prototype such that the getter sets an own property on the instance
>> if it doesn't exist, then returns that value
>>
>> What I mean is this:
>>
>> ```js
>> class Example {
>>   //classField = class{}; //Error
>>   otherField=[ "foo", "bar"];
>> }
>>
>> class ES6Example {
>>   //classField ignored for this example since it was an error.
>>   get otherField() {
>>     if ((this instanceof ES6Example) &&
>> !this.hasOwnProperty("otherField"))
>>       this.otherField = [ "foo", "bar" ];
>>     return this.otherField;
>>   }
>> }
>> ```
>>
>> Done this way, any code expecting early assignment of a field being used
>> as though it were "abstract" will still work as expected.
>>
>> On Thu, Aug 30, 2018 at 4:38 PM doodad-js Admin <doodadjs at gmail.com>
>> wrote:
>>
>>> I'm late to the party, but I've found a solution for my non-loved
>>> framework : have another constructor called before "super", which fills a
>>> faked "this" and a faked "args" then replicated values to "this" after
>>> doing "super(...fakedArgs)".
>>>
>>>
>>> https://github.com/doodadjs/doodad-js/blob/v9.1.3/src/common/Bootstrap.js#L5320-L5330
>>>
>>> -----Original Message-----
>>> From: Isiah Meadows <isiahmeadows at gmail.com>
>>> Sent: Sunday, August 26, 2018 3:29 PM
>>> To: Logan Smyth <loganfsmyth at gmail.com>
>>> Cc: Ben Wiley <therealbenwiley at gmail.com>; es-discuss <
>>> es-discuss at mozilla.org>
>>> Subject: Re: constructor, super, and data members issue
>>>
>>> Yeah, I was more focused on the static class side of things, because I
>>> thought they were referring to that. Class instance fields are different,
>>> and so of course, those are never set on the prototype unless for whatever
>>> reason, the parent constructor returns `Object.getPrototypeOf(this)`
>>> instead of letting it default to the normal `this`.
>>>
>>> My bad, and you are correct.
>>>
>>> -----
>>>
>>> Isiah Meadows
>>> contact at isiahmeadows.com
>>> www.isiahmeadows.com
>>>
>>> On Sun, Aug 26, 2018 at 12:20 PM Logan Smyth <loganfsmyth at gmail.com>
>>> wrote:
>>> >
>>> > Static class fields run their initializers and define the properties
>>> > at declaration time, and class constructors have the parent class as
>>> > the `[[Prototype]]`, so static field values are inherited. I think
>>> this is adding to confusion though, because while that's absolutely true,
>>> that is not applicable in the same way to non-static class fields, which is
>>> what this original email is focused on. You could indeed also address this
>>> with static properties in a proper ES6 environment as ``` class Base {
>>> >   static idAttribute = "id";
>>> >
>>> >   constructor() {
>>> >        this.idAttribute = new.target.idAttribute;
>>> >   }
>>> > }
>>> > class Derived extends Base {
>>> >   static idAttribute = "_id";
>>> >
>>> >   constructor() {
>>> >        super();
>>> >   }
>>> > }
>>> > ```
>>> >
>>> > On Sun, Aug 26, 2018 at 10:35 AM Isiah Meadows <isiahmeadows at gmail.com>
>>> wrote:
>>> >>
>>> >> Every object, including functions, have an internal prototype.
>>> Functions normally have one set to `Function.prototype`, and objects
>>> normally inherit from `Object.prototype` at least indirectly. But because
>>> of how prototypes work, the only requirement for something to be used as a
>>> prototype is that it must be an object. So you can do
>>> `Object.create(someFunction)` and although you can't call it (it's not a
>>> callable object), that object inherits all the properties and methods from
>>> that function. `class` in JavaScript is just sugar over a common pattern
>>> (really complex sugar requiring `new.target` to emulate, but still sugar),
>>> not an entirely new concept, and it all builds off of prototypes.
>>> Specifically, the instance prototype inherits from the parent prototype,
>>> and the class constructor itself inherits from the parent constructor.
>>> That's why if you declare a static `call` method on a parent class, you can
>>> still access and use it in the subclass.
>>> >> On Sat, Aug 25, 2018 at 19:58 Ben Wiley <therealbenwiley at gmail.com>
>>> wrote:
>>> >>>
>>> >>> How can they be prototypically inherited if they don't live on the
>>> prototype? I feel like I'm missing something.
>>> >>>
>>> >>> Le sam. 25 août 2018 19 h 53, Isiah Meadows <isiahmeadows at gmail.com>
>>> a écrit :
>>> >>>>
>>> >>>> Class fields are prototypically inherited just like via `Object
>>> create`. This is more useful than you might think, and it's the main reason
>>> anyone actually cares about static fields beyond namespacing.
>>> >>>> On Sat, Aug 25, 2018 at 14:36 Ben Wiley <therealbenwiley at gmail.com>
>>> wrote:
>>> >>>>>
>>> >>>>> All this just reminds me of *my opinion* that class fields is a
>>> borrowed concept from statically typed languages that is misplaced in a
>>> dynamically typed languages like JavaScript.
>>> >>>>>
>>> >>>>> In C++ I use class fields to declare what properties will be
>>> allocated and instantiated when a new class member is constructed.
>>> >>>>>
>>> >>>>> In the ES proposal for class fields we mimic this type of behavior
>>> by instantiating properties on the object when it's constructed, but
>>> there's no runtime guarantee that this set of properties will remain the
>>> same.
>>> >>>>>
>>> >>>>> There's no reason not to put this in the constructor, and although
>>> putting class fields on the prototype is debatably not the best idea, it
>>> would be the only scenario where we get some kind of new helpful behavior
>>> out of it.
>>> >>>>>
>>> >>>>> Ben
>>> >>>>>
>>> >>>>> Le sam. 25 août 2018 14 h 25, Augusto Moura <
>>> augusto.borgesm at gmail.com> a écrit :
>>> >>>>>>
>>> >>>>>> 24-08-2018 19:29, Aaron Gray <aaronngray.lists at gmail.com>:
>>> >>>>>>
>>> >>>>>> >
>>> >>>>>> > Yeah it does look like its badly "broken by design".
>>> >>>>>> >
>>> >>>>>>
>>> >>>>>> Why this behaviour is broken? Every OOP language that I worked
>>> >>>>>> with behaves de same way, and there's not many developers
>>> >>>>>> complaining about it. If you want to use a property that might be
>>> >>>>>> overrided in a subclasss you need to use a method and make the
>>> >>>>>> source of the data more versatile (in Java and others similiar
>>> >>>>>> languages we have to implement it using getter methods). Luckily
>>> >>>>>> Javascript doesn't need getter and setters methods to make a
>>> >>>>>> property overridable because of getter and setters descriptors,
>>> >>>>>> so we can workaround the first example
>>> >>>>>> easily:
>>> >>>>>>
>>> >>>>>> ``` js
>>> >>>>>> class Bar {
>>> >>>>>>   bar = 'in bar';
>>> >>>>>>
>>> >>>>>>   constructor() {
>>> >>>>>>     console.log(this.bar)
>>> >>>>>>   }
>>> >>>>>> }
>>> >>>>>>
>>> >>>>>> class Foo extends Bar {
>>> >>>>>>   _initiedSuper = false;
>>> >>>>>>   _bar = 'in foo';
>>> >>>>>>
>>> >>>>>>   constructor() {
>>> >>>>>>     super();
>>> >>>>>>     this._initiedSuper = true;
>>> >>>>>>   }
>>> >>>>>>
>>> >>>>>>   get bar() {
>>> >>>>>>     return this._bar;
>>> >>>>>>   }
>>> >>>>>>
>>> >>>>>>   set bar(val) {
>>> >>>>>>     if (this._initiedSuper) {
>>> >>>>>>       this._bar = val;
>>> >>>>>>     }
>>> >>>>>>   }
>>> >>>>>> }
>>> >>>>>>
>>> >>>>>> new Foo(); // will log 'in foo'
>>> >>>>>> ```
>>> >>>>>>
>>> >>>>>> *I have to say the relaying that the super constructor will use
>>> >>>>>> the bar property and workarounding it **is a bad practice** and
>>> >>>>>> should be avoided at any costs. The contract with the super class
>>> >>>>>> constructor should rely only on the super call, these situations
>>> >>>>>> just reveal bad design choices in the super class. Logan Smyth
>>> >>>>>> example is the correct answer to this problem*
>>> >>>>>>
>>> >>>>>>
>>> >>>>>> 25-08-2018 01:28, Jordan Harband <ljharb at gmail.com>:
>>> >>>>>>
>>> >>>>>> >
>>> >>>>>> > Personally I think a design where the superclass relies on any
>>> >>>>>> > part of the subclass is "broken by design"; but certainly
>>> >>>>>> > there's ways you can achieve that.
>>> >>>>>> >
>>> >>>>>>
>>> >>>>>> Of course is not broken. The super class has a contract with a
>>> >>>>>> parametrized option, it can be used in subclasses or just in a
>>> >>>>>> constructor call `new Base({ idAttribute: 'foo' })`, if it has a
>>> >>>>>> default value for that is not a sub class concern. When
>>> >>>>>> refactoring code adding defaults and "lifting" parameters are
>>> >>>>>> very common ~not only on OOP~ and relying that the super class is
>>> >>>>>> using some property in the constructor is the real "broken by
>>> design".
>>> >>>>>> _______________________________________________
>>> >>>>>> 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
>>>
>>>
>>>
>>> ---
>>> This email has been checked for viruses by AVG.
>>> https://www.avg.com
>>>
>>> _______________________________________________
>>> 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/20180903/b528e839/attachment-0001.html>


More information about the es-discuss mailing list