constructor, super, and data members issue
Aaron, congratulations! You just tripped over a new reason for me to revive
issue #123. The only way to get that to work is to have the default values
on the prototype. The problem comes because this
doesn't even have a
value until the last call to super()
returns. If a class
doesn't have a
base class
it essentially has Object as a base class
and super
is
implicitly called. So unless the default public field values are on the
prototype, there's literally no way to have them initialized before the
base classes are initialized.
Aaron, congratulations! You just tripped over a new reason for me to revive issue #123. The only way to get that to work is to have the default values on the prototype. The problem comes because `this` doesn't even have a value until the last call to `super()` returns. If a `class` doesn't have a base `class` it essentially has Object as a base `class` and `super` is implicitly called. So unless the default public field values are on the prototype, there's literally no way to have them initialized before the base classes are initialized. On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> wrote: > I am having an issue with order semantics regarding > https://github.com/tc39/proposal-class-fields with derived classes > defining or overriding data member values that are used in the base class > constructor for initialization of properties of the class. > > This means the Super Class / Base Class'es constructor does not yet have > access to the default field values of the derived class it is initiating. > > class Base { > constructor() { > .... > .. idAttribute .. > .... > } > idAttribute = 'id'; > } > class Derived extends Base { > constructor() { > super(); > .... > } > idAttribute = '_id'; > } > > All would mean having a separate initialize() function, but even this > solution is flawed when there is a third level in the hierarchy. And as > super() is required it means there seems to be no way round this issue. The > only way I can see is some form of override keyword ? > > > Has anyone got any solutions to this issue or work arounds ? > -- > Aaron Gray > > Independent Open Source Software Engineer, Computer Language Researcher, > Information Theorist, and amateur computer scientist. > _______________________________________________ > 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/20180824/c17fb38f/attachment.html>
I'm afraid that still wouldn't solve the problem; the superclass's code is
all 100% completed before the subclass has this
available.
I'm afraid that still wouldn't solve the problem; the superclass's code is all 100% completed before the subclass has `this` available. On Fri, Aug 24, 2018 at 1:52 PM, Ranando King <kingmph at gmail.com> wrote: > Aaron, congratulations! You just tripped over a new reason for me to > revive issue #123. The only way to get that to work is to have the default > values on the prototype. The problem comes because `this` doesn't even have > a value until the last call to `super()` returns. If a `class` doesn't have > a base `class` it essentially has Object as a base `class` and `super` is > implicitly called. So unless the default public field values are on the > prototype, there's literally no way to have them initialized before the > base classes are initialized. > > On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> > wrote: > >> I am having an issue with order semantics regarding https://github.com/ >> tc39/proposal-class-fields with derived classes defining or overriding >> data member values that are used in the base class constructor for >> initialization of properties of the class. >> >> This means the Super Class / Base Class'es constructor does not yet have >> access to the default field values of the derived class it is initiating. >> >> class Base { >> constructor() { >> .... >> .. idAttribute .. >> .... >> } >> idAttribute = 'id'; >> } >> class Derived extends Base { >> constructor() { >> super(); >> .... >> } >> idAttribute = '_id'; >> } >> >> All would mean having a separate initialize() function, but even this >> solution is flawed when there is a third level in the hierarchy. And as >> super() is required it means there seems to be no way round this issue. The >> only way I can see is some form of override keyword ? >> >> >> Has anyone got any solutions to this issue or work arounds ? >> -- >> Aaron Gray >> >> Independent Open Source Software Engineer, Computer Language Researcher, >> Information Theorist, and amateur computer scientist. >> _______________________________________________ >> 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/20180824/04e86141/attachment.html>
Yeah it does look like its badly "broken by design".
Yeah it does look like its badly "broken by design". On Fri, 24 Aug 2018 at 22:13, Jordan Harband <ljharb at gmail.com> wrote: > I'm afraid that still wouldn't solve the problem; the superclass's code is > all 100% completed before the subclass has `this` available. > > On Fri, Aug 24, 2018 at 1:52 PM, Ranando King <kingmph at gmail.com> wrote: > >> Aaron, congratulations! You just tripped over a new reason for me to >> revive issue #123. The only way to get that to work is to have the default >> values on the prototype. The problem comes because `this` doesn't even have >> a value until the last call to `super()` returns. If a `class` doesn't have >> a base `class` it essentially has Object as a base `class` and `super` is >> implicitly called. So unless the default public field values are on the >> prototype, there's literally no way to have them initialized before the >> base classes are initialized. >> >> On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> >> wrote: >> >>> I am having an issue with order semantics regarding >>> https://github.com/tc39/proposal-class-fields with derived classes >>> defining or overriding data member values that are used in the base class >>> constructor for initialization of properties of the class. >>> >>> This means the Super Class / Base Class'es constructor does not yet have >>> access to the default field values of the derived class it is initiating. >>> >>> class Base { >>> constructor() { >>> .... >>> .. idAttribute .. >>> .... >>> } >>> idAttribute = 'id'; >>> } >>> class Derived extends Base { >>> constructor() { >>> super(); >>> .... >>> } >>> idAttribute = '_id'; >>> } >>> >>> All would mean having a separate initialize() function, but even this >>> solution is flawed when there is a third level in the hierarchy. And as >>> super() is required it means there seems to be no way round this issue. The >>> only way I can see is some form of override keyword ? >>> >>> >>> Has anyone got any solutions to this issue or work arounds ? >>> -- >>> Aaron Gray >>> >>> Independent Open Source Software Engineer, Computer Language Researcher, >>> Information Theorist, and amateur computer scientist. >>> _______________________________________________ >>> 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 >> >> > -- Aaron Gray Independent Open Source Software Engineer, Computer Language Researcher, Information Theorist, and amateur computer scientist. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180824/716a90bc/attachment.html>
Generally if something is required during construction, it would be best to pass it down as part of the constructor options. For example, you could do
class Base {
constructor({ idAttribute = "id"}) {
this.idAttribute = idAttribute;
}
}
class Derived extends Base {
constructor() {
super({
idAttribute: '_id'
});
}
}
I don't think class fields would be a good way to conceptually do this kind of thing.
Generally if something is required during construction, it would be best to pass it down as part of the constructor options. For example, you could do ``` class Base { constructor({ idAttribute = "id"}) { this.idAttribute = idAttribute; } } class Derived extends Base { constructor() { super({ idAttribute: '_id' }); } } ``` I don't think class fields would be a good way to conceptually do this kind of thing. On Fri, Aug 24, 2018 at 2:56 PM, Aaron Gray <aaronngray.lists at gmail.com> wrote: > Yeah it does look like its badly "broken by design". > > On Fri, 24 Aug 2018 at 22:13, Jordan Harband <ljharb at gmail.com> wrote: > >> I'm afraid that still wouldn't solve the problem; the superclass's code >> is all 100% completed before the subclass has `this` available. >> >> On Fri, Aug 24, 2018 at 1:52 PM, Ranando King <kingmph at gmail.com> wrote: >> >>> Aaron, congratulations! You just tripped over a new reason for me to >>> revive issue #123. The only way to get that to work is to have the default >>> values on the prototype. The problem comes because `this` doesn't even have >>> a value until the last call to `super()` returns. If a `class` doesn't have >>> a base `class` it essentially has Object as a base `class` and `super` is >>> implicitly called. So unless the default public field values are on the >>> prototype, there's literally no way to have them initialized before the >>> base classes are initialized. >>> >>> On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> >>> wrote: >>> >>>> I am having an issue with order semantics regarding https://github.com/ >>>> tc39/proposal-class-fields with derived classes defining or overriding >>>> data member values that are used in the base class constructor for >>>> initialization of properties of the class. >>>> >>>> This means the Super Class / Base Class'es constructor does not yet >>>> have access to the default field values of the derived class it is >>>> initiating. >>>> >>>> class Base { >>>> constructor() { >>>> .... >>>> .. idAttribute .. >>>> .... >>>> } >>>> idAttribute = 'id'; >>>> } >>>> class Derived extends Base { >>>> constructor() { >>>> super(); >>>> .... >>>> } >>>> idAttribute = '_id'; >>>> } >>>> >>>> All would mean having a separate initialize() function, but even this >>>> solution is flawed when there is a third level in the hierarchy. And as >>>> super() is required it means there seems to be no way round this issue. The >>>> only way I can see is some form of override keyword ? >>>> >>>> >>>> Has anyone got any solutions to this issue or work arounds ? >>>> -- >>>> Aaron Gray >>>> >>>> Independent Open Source Software Engineer, Computer Language >>>> Researcher, Information Theorist, and amateur computer scientist. >>>> _______________________________________________ >>>> 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 >>> >>> >> > > -- > Aaron Gray > > Independent Open Source Software Engineer, Computer Language Researcher, > Information Theorist, and amateur computer scientist. > > _______________________________________________ > 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/20180824/091c3627/attachment-0001.html>
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.
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. On Fri, Aug 24, 2018 at 4:34 PM, Logan Smyth <loganfsmyth at gmail.com> wrote: > Generally if something is required during construction, it would be best > to pass it down as part of the constructor options. For example, you could > do > ``` > class Base { > constructor({ idAttribute = "id"}) { > this.idAttribute = idAttribute; > } > } > > class Derived extends Base { > constructor() { > super({ > idAttribute: '_id' > }); > } > } > ``` > > I don't think class fields would be a good way to conceptually do this > kind of thing. > > > On Fri, Aug 24, 2018 at 2:56 PM, Aaron Gray <aaronngray.lists at gmail.com> > wrote: > >> Yeah it does look like its badly "broken by design". >> >> On Fri, 24 Aug 2018 at 22:13, Jordan Harband <ljharb at gmail.com> wrote: >> >>> I'm afraid that still wouldn't solve the problem; the superclass's code >>> is all 100% completed before the subclass has `this` available. >>> >>> On Fri, Aug 24, 2018 at 1:52 PM, Ranando King <kingmph at gmail.com> wrote: >>> >>>> Aaron, congratulations! You just tripped over a new reason for me to >>>> revive issue #123. The only way to get that to work is to have the default >>>> values on the prototype. The problem comes because `this` doesn't even have >>>> a value until the last call to `super()` returns. If a `class` doesn't have >>>> a base `class` it essentially has Object as a base `class` and `super` is >>>> implicitly called. So unless the default public field values are on the >>>> prototype, there's literally no way to have them initialized before the >>>> base classes are initialized. >>>> >>>> On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> >>>> wrote: >>>> >>>>> I am having an issue with order semantics regarding >>>>> https://github.com/tc39/proposal-class-fields with derived classes >>>>> defining or overriding data member values that are used in the base class >>>>> constructor for initialization of properties of the class. >>>>> >>>>> This means the Super Class / Base Class'es constructor does not yet >>>>> have access to the default field values of the derived class it is >>>>> initiating. >>>>> >>>>> class Base { >>>>> constructor() { >>>>> .... >>>>> .. idAttribute .. >>>>> .... >>>>> } >>>>> idAttribute = 'id'; >>>>> } >>>>> class Derived extends Base { >>>>> constructor() { >>>>> super(); >>>>> .... >>>>> } >>>>> idAttribute = '_id'; >>>>> } >>>>> >>>>> All would mean having a separate initialize() function, but even this >>>>> solution is flawed when there is a third level in the hierarchy. And as >>>>> super() is required it means there seems to be no way round this issue. The >>>>> only way I can see is some form of override keyword ? >>>>> >>>>> >>>>> Has anyone got any solutions to this issue or work arounds ? >>>>> -- >>>>> Aaron Gray >>>>> >>>>> Independent Open Source Software Engineer, Computer Language >>>>> Researcher, Information Theorist, and amateur computer scientist. >>>>> _______________________________________________ >>>>> 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 >>>> >>>> >>> >> >> -- >> Aaron Gray >> >> Independent Open Source Software Engineer, Computer Language Researcher, >> Information Theorist, and amateur computer scientist. >> >> _______________________________________________ >> 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/20180824/1274dc40/attachment.html>
On Sat, 25 Aug 2018 at 00:35, Logan Smyth <loganfsmyth at gmail.com> wrote:
Generally if something is required during construction, it would be best to pass it down as part of the constructor options. For example, you could do
class Base { constructor({ idAttribute = "id"}) { this.idAttribute = idAttribute; } } class Derived extends Base { constructor() { super({ idAttribute: '_id' }); } }
I had derived a simular solution.
I don't think class fields would be a good way to conceptually do this kind of thing.
It was neat for what I wanted to do.
On Sat, 25 Aug 2018 at 00:35, Logan Smyth <loganfsmyth at gmail.com> wrote: > Generally if something is required during construction, it would be best > to pass it down as part of the constructor options. For example, you could > do > ``` > class Base { > constructor({ idAttribute = "id"}) { > this.idAttribute = idAttribute; > } > } > > class Derived extends Base { > constructor() { > super({ > idAttribute: '_id' > }); > } > } > ``` > I had derived a simular solution. > I don't think class fields would be a good way to conceptually do this > kind of thing. > It was neat for what I wanted to do. > > > On Fri, Aug 24, 2018 at 2:56 PM, Aaron Gray <aaronngray.lists at gmail.com> > wrote: > >> Yeah it does look like its badly "broken by design". >> >> On Fri, 24 Aug 2018 at 22:13, Jordan Harband <ljharb at gmail.com> wrote: >> >>> I'm afraid that still wouldn't solve the problem; the superclass's code >>> is all 100% completed before the subclass has `this` available. >>> >>> On Fri, Aug 24, 2018 at 1:52 PM, Ranando King <kingmph at gmail.com> wrote: >>> >>>> Aaron, congratulations! You just tripped over a new reason for me to >>>> revive issue #123. The only way to get that to work is to have the default >>>> values on the prototype. The problem comes because `this` doesn't even have >>>> a value until the last call to `super()` returns. If a `class` doesn't have >>>> a base `class` it essentially has Object as a base `class` and `super` is >>>> implicitly called. So unless the default public field values are on the >>>> prototype, there's literally no way to have them initialized before the >>>> base classes are initialized. >>>> >>>> On Fri, Aug 24, 2018 at 3:15 PM Aaron Gray <aaronngray.lists at gmail.com> >>>> wrote: >>>> >>>>> I am having an issue with order semantics regarding >>>>> https://github.com/tc39/proposal-class-fields with derived classes >>>>> defining or overriding data member values that are used in the base class >>>>> constructor for initialization of properties of the class. >>>>> >>>>> This means the Super Class / Base Class'es constructor does not yet >>>>> have access to the default field values of the derived class it is >>>>> initiating. >>>>> >>>>> class Base { >>>>> constructor() { >>>>> .... >>>>> .. idAttribute .. >>>>> .... >>>>> } >>>>> idAttribute = 'id'; >>>>> } >>>>> class Derived extends Base { >>>>> constructor() { >>>>> super(); >>>>> .... >>>>> } >>>>> idAttribute = '_id'; >>>>> } >>>>> >>>>> All would mean having a separate initialize() function, but even this >>>>> solution is flawed when there is a third level in the hierarchy. And as >>>>> super() is required it means there seems to be no way round this issue. The >>>>> only way I can see is some form of override keyword ? >>>>> >>>>> >>>>> Has anyone got any solutions to this issue or work arounds ? >>>>> -- >>>>> Aaron Gray >>>>> >>>>> Independent Open Source Software Engineer, Computer Language >>>>> Researcher, Information Theorist, and amateur computer scientist. >>>>> _______________________________________________ >>>>> 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 >>>> >>>> >>> >> >> -- >> Aaron Gray >> >> Independent Open Source Software Engineer, Computer Language Researcher, >> Information Theorist, and amateur computer scientist. >> >> _______________________________________________ >> es-discuss mailing list >> es-discuss at mozilla.org >> https://mail.mozilla.org/listinfo/es-discuss >> >> > -- Aaron Gray Independent Open Source Software Engineer, Computer Language Researcher, Information Theorist, and amateur computer scientist. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180825/4f35ea63/attachment.html>
Base cases that take dependencies upon information potentially supplied by subclass have to be intentionally design to make that work. And the chosen design should be document as part of its subclassing contract. For the example shown there is there is a long known pattern that can be used:
class Base { constructor() { .... .. idAttribute .. .... } idAttribute = this.__idInitializer(); //initial id value may be supplied by a subclass __idInitialier() { // override this method if you want your subclass to provide an alternative initial idAttribute value // the subclass override method should not be dependent upon subclass fields. return ‘id’; ’} }
class Derived extends Base { constructor() { super(); .... } __idInitializer() {return ‘_id’} }
Base cases that take dependencies upon information potentially supplied by subclass have to be intentionally design to make that work. And the chosen design should be document as part of its subclassing contract. For the example shown there is there is a long known pattern that can be used: class Base { constructor() { .... .. idAttribute .. .... } idAttribute = this.__idInitializer(); //initial id value may be supplied by a subclass __idInitialier() { // override this method if you want your subclass to provide an alternative initial idAttribute value // the subclass override method should not be dependent upon subclass fields. return ‘id’; ’} } class Derived extends Base { constructor() { super(); .... } __idInitializer() {return ‘_id’} } -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180825/e77cda05/attachment.html>
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:
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".
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".
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 :
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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180825/c1b8c511/attachment.html>
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.
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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180825/751fb678/attachment.html>
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 :
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 >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180825/fc4b3ef5/attachment-0001.html>
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.
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 >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180826/d0595a68/attachment.html>
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();
}
}
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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180826/54c9d136/attachment-0001.html>
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
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
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)".
doodadjs/doodad-js/blob/v9.1.3/src/common/Bootstrap.js#L5320
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
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:
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.
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 > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180903/ff82b885/attachment-0001.html>
Even with the suggestion I've made, I would still recommend keeping the post-super() initialization function. It would simply get all of the class fields from the prototype. Those that haven't already been initialized would be, guaranteeing that all fields that need to be initialized would be by the time they are needed in the code.
Even with the suggestion I've made, I would still recommend keeping the post-super() initialization function. It would simply get all of the class fields from the prototype. Those that haven't already been initialized would be, guaranteeing that all fields that need to be initialized would be by the time they are needed in the code. On Mon, Sep 3, 2018 at 2: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 >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://mail.mozilla.org/pipermail/es-discuss/attachments/20180903/a1b604cd/attachment-0001.html>
field = (function () { return class { }; }())
- how exactly would you
propose banning creating a class inside class fields?
`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/808af98e/attachment-0001.html>
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.
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>
I'd say that defining a class directly in a class field is extremely niche, and by doing that, the user "should know what they've done" too.
I'd say that defining a class directly in a class field is extremely niche, and by doing that, the user "should know what they've done" too. On Mon, Sep 3, 2018 at 3:44 PM, Ranando King <kingmph at gmail.com> wrote: > 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/d21d5955/attachment-0001.html>
With that line of thinking, the user "should always know what they've done", meaning there's no need to avoid functionality in favor of avoiding foot-guns. Yet... As far as assigning a class definition directly to a field, developers coming to JS/ES from other languages (especially Java) may not think so as it is fairly common practice in some languages to define one class completely inside another, but not inside any method of the outer class. The exposure of such inner classes varies with the need for which it was written. I wouldn't be so quick to discount this kind of assignment as "niche". In either case, even if it does turn out to be niche and we ignore that little restriction, that has little bearing on the potential solution I've offered. This approach allows the value initializer to live in a getter for the property on the prototype. The first access to the property puts the value uniquely onto the instance. The example code isn't perfect, but it does cover the basic idea. It might be better written like this:
class Example {
//classField = class{}; //Error
otherField=[ "foo", "bar"];
}
class ES6Example {
//classField ignored for this example since it was an error.
get otherField() {
let _otherField_InitialValue_ = [ "foo", "bar" ];
if ((this instanceof ES6Example) &&
!this.hasOwnProperty("otherField") &&
Object.isExtensible(this) &&
Object.getOwnPropertyDefinition(this.__proto__,
"otherField").configurable) {
this.otherField = _otherField_InitialValue_;
}
return _otherField_InitialValue_;
}
}
With that line of thinking, the user "should **always** know what they've done", meaning there's no need to avoid functionality in favor of avoiding foot-guns. Yet... As far as assigning a class definition directly to a field, developers coming to JS/ES from other languages (especially Java) may not think so as it is fairly common practice in some languages to define one class completely inside another, but not inside any method of the outer class. The exposure of such inner classes varies with the need for which it was written. I wouldn't be so quick to discount this kind of assignment as "niche". In either case, even if it does turn out to be niche and we ignore that little restriction, that has little bearing on the potential solution I've offered. This approach allows the value initializer to live in a getter for the property on the prototype. The first access to the property puts the value uniquely onto the instance. The example code isn't perfect, but it does cover the basic idea. It might be better written like this: ```js class Example { //classField = class{}; //Error otherField=[ "foo", "bar"]; } class ES6Example { //classField ignored for this example since it was an error. get otherField() { let _otherField_InitialValue_ = [ "foo", "bar" ]; if ((this instanceof ES6Example) && !this.hasOwnProperty("otherField") && Object.isExtensible(this) && Object.getOwnPropertyDefinition(this.__proto__, "otherField").configurable) { this.otherField = _otherField_InitialValue_; } return _otherField_InitialValue_; } } ``` On Tue, Sep 4, 2018 at 12:39 AM Jordan Harband <ljharb at gmail.com> wrote: > I'd say that defining a class directly in a class field is extremely > niche, and by doing that, the user "should know what they've done" too. > > On Mon, Sep 3, 2018 at 3:44 PM, Ranando King <kingmph at gmail.com> wrote: > >> 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/20180904/194350b1/attachment-0001.html>
I am having an issue with order semantics regarding tc39/proposal-class-fields with derived classes defining or overriding data member values that are used in the base class constructor for initialization of properties of the class.
This means the Super Class / Base Class'es constructor does not yet have access to the default field values of the derived class it is initiating.
class Derived extends Base { constructor() { super(); .... } idAttribute = '_id'; }
All would mean having a separate initialize() function, but even this solution is flawed when there is a third level in the hierarchy. And as super() is required it means there seems to be no way round this issue. The only way I can see is some form of override keyword ?
Has anyone got any solutions to this issue or work arounds ?