<div dir="ltr">> Contrary to what you may have been led to believe, 
the definition of a class is its prototype. There are those who refuse 
to accept this reality, and that's fine. But if you make the wrong 
assumptions as a result of an incorrect understanding, the results won't
 turn out how you want.<div><br></div><div>Can you please keep this extremely condescending tone out of these discussions? I don't know how you expect people to get on board with your proposals when you constantly imply that those that disagree with you don't know what they are talking about.<br></div><div><br></div><div>> The constructor only comes into play after a new object has been created with the corresponding prototype attached.</div><div><br></div><div>A prototype with an entirely different constructor is an entirely different class. The behavior of a constructor is critical to the behavior of an instance of a class, and in an ideal world is responsible for defining all of the own properties of the instance. I don't understand how a prototype on its own could be considered to represent the class as a whole.<br></div><div><br></div><div>> Constructor comparisons can easily be spoofed simply by Proxying the constructor.</div><div><br></div><div>I'm not sure I see how that would be any different for intercepting the `.prototype` access.</div><div><br></div><div>> With `final`, the point is that a `class` that extends from a `final class` **<b>cannot be defined</b>**, not simply "cannot be instantiated". Even without instantiating, a defined `class` can still be used.</div><div><br></div><div>I don't disagree that it it would throw as early as possible in an ideal world, just that it seems to complicate the implementation dramatically with out a ton of benefit that I can see. I think it does depend on your overall goal though. Is `final` meant to mean that the prototype may never exist anywhere but the head of the prototype chain, or just that a subclass may not be constructed? That I guess goes to Isiah's questions about `Object.create` and such as well. It seems like 99% of the time I'd be much more interested in preventing creation of subclasses. I don't particularly care about the exact location of an object in the prototype chain.<br></div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, Dec 2, 2018 at 6:25 PM Ranando King <<a href="mailto:kingmph@gmail.com">kingmph@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr">@Logan<div><br></div><div>> It would not be good if you could sidestep `abstract` by taking the prototype from the class and making a new constructor for it.</div><div><br><div>That's precisely why it's a prototype test and not a constructor test. Everything that defines the initial "shape" of the class is on the prototype. The constructor only comes into play after a new object has been created with the corresponding prototype attached. If the prototype of the constructor being called matches the prototype of newTarget, and that prototype has been flagged as abstract, the new object creation is halted immediately. Constructor comparisons can easily be spoofed simply by Proxying the constructor. Where target would be the un-Proxied constructor, newTarget would be the Proxy. They wouldn't match so the abstract test would fail and an object would be constructed.</div><div><br></div><div>Contrary to what you may have been led to believe, the definition of a class is its prototype. There are those who refuse to accept this reality, and that's fine. But if you make the wrong assumptions as a result of an incorrect understanding, the results won't turn out how you want.</div></div><div><br></div><div>With `final`, the point is that a `class` that extends from a `final class` **<b>cannot be defined</b>**, not simply "cannot be instantiated". Even without instantiating, a defined `class` can still be used.</div><div><br></div><div>>...it would essentially just be the negation of the check `abstract` was doing already.</div><div><br></div><div>That's precisely correct. These 2 new tokens are the polar opposites of each other. One restricts construction to cases where the prototypes of `target` and `newTarget` match (`final`), while the other requires that they don't match (`abstract`). That's also the reason they cannot be used together.</div><br><div>@Isiah<br></div><div>Sounds like part of what you're looking for is abstract methods rather than an `abstract class`. I wasn't targeting that. If I were, that would be something to add to proposal-common-class-modifiers. If I were to look at what you're describing more holistically, you're looking for "interface", a way to set up a contract for what's supposed to be there and require it all to be present. I wasn't targeting that either. In fact, that would probably be a good proposal all by itself. I'll give an implementation for that some thought. However, with this proposal, all I'm thinking about is inheritance constraints. </div><div><br></div><div>As for `final`, I need you to convince me that it's worth while preventing Object.create and Object.setPrototype. It's shouldn't be that difficult to do, but I don't have an understanding of why you'd want to. Especially when you consider that when some form of private goes in (assuming it's not Symbol.Private) class instances will be quite a bit different than vanilla objects.</div><div><br></div><div>I get that `final` is something not seen in dynamic languages (outside the JVM), but it is a useful tool in giving developers control over how their code can be used. Isn't that part of the point of trying to implement private data in ES?</div></div><br><div class="gmail_quote"><div dir="ltr">On Sun, Dec 2, 2018 at 4:19 PM Isiah Meadows <<a href="mailto:isiahmeadows@gmail.com" target="_blank">isiahmeadows@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">@Logan If this helps explain my stance, I'm skeptical of the use, and<br>
it really disrupts the consistency of JS's object model quite a bit.<br>
It makes sense to enforce at a static level, but not really at a<br>
dynamic runtime level. Also, this is lacking precedent in other<br>
dynamic languages with classes: Python, Ruby, Smalltalk, Lua, Io, and<br>
pretty much every other dynamic language with class- or<br>
prototype-based inheritance (that wasn't made for the JVM) doesn't<br>
support final classes. Python (IIRC through a decorator) and Ruby<br>
support abstract methods, but not final classes/methods.<br>
<br>
-----<br>
<br>
Isiah Meadows<br>
<a href="mailto:contact@isiahmeadows.com" target="_blank">contact@isiahmeadows.com</a><br>
<a href="http://www.isiahmeadows.com" rel="noreferrer" target="_blank">www.isiahmeadows.com</a><br>
<br>
On Sun, Dec 2, 2018 at 5:10 PM Logan Smyth <<a href="mailto:loganfsmyth@gmail.com" target="_blank">loganfsmyth@gmail.com</a>> wrote:<br>
><br>
> Wouldn't it be better `abstract`'s `target.prototype === newTarget.prototype` check to be `target === newTarget`? It's not really the prototype that is at issue here, it is the class constructor itself. It would not be good if you could sidestep `abstract` by taking the prototype from the class and making a new constructor for it.<br>
><br>
> For `final` is it worth throwing an `extends` time vs just throwing when the class is instantiated? It seems like `final` would otherwise require new private state on the constructor itself, where otherwise it would essentially just be the negation of the check `abstract` was doing already.<br>
><br>
> Also, if those make sense, what do we gain by having these be keywords instead of decorators?<br>
><br>
> On Sun, Dec 2, 2018 at 1:43 PM Isiah Meadows <<a href="mailto:isiahmeadows@gmail.com" target="_blank">isiahmeadows@gmail.com</a>> wrote:<br>
>><br>
>> For `abstract`, I could see that being three things:<br>
>><br>
>> - Throw a reference error if an abstract method is called with no concrete implementation<br>
>> - Throw a type error if the constructor is called without its abstract methods implemented<br>
>> - Throw a type error if a subclass fails to implement all remaining abstract methods and is not itself abstract<br>
>><br>
>> Each of these could be reasonably tacked on at the end.<br>
>><br>
>> For `final`, you'll need to create a way to block all means of `Object.create`, with class constructors being the sole exception. That complicates the mechanism tremendously, since prototype-based inheritance alone can't enforce this unless you make `Object.setPrototypeOf(obj, parent)` no longer directly equivalent to `obj.[[Prototype]] = parent`.<br>
>> On Sun, Dec 2, 2018 at 16:28 Ranando King <<a href="mailto:kingmph@gmail.com" target="_blank">kingmph@gmail.com</a>> wrote:<br>
>>><br>
>>> Object.create and Object.setPrototypeOf operate on a different level than what I'm targeting. I can conceive of a means to make even these functions respect these tokens. However, if I were going to do that, I'd want these tokens to be applicable to objects and functions directly. Reflect.construct is essentially part of the process for `new` and would be required to respect these tokens. I'm still open on how far the effect of these tokens should extend.<br>
>>><br>
>>> On Sun, Dec 2, 2018 at 3:20 PM Isiah Meadows <<a href="mailto:isiahmeadows@gmail.com" target="_blank">isiahmeadows@gmail.com</a>> wrote:<br>
>>>><br>
>>>> How would this interop with `Object.create`, `Reflect.construct`, and `Object.setPrototypeOf`?<br>
>>>> On Sun, Dec 2, 2018 at 16:16 Ranando King <<a href="mailto:kingmph@gmail.com" target="_blank">kingmph@gmail.com</a>> wrote:<br>
>>>>><br>
>>>>> This proposal is intended to add `abstract` and `final` to `class` definitions so as to modify the inheritability of a class.<br>
>>>>><br>
>>>>> <a href="https://github.com/rdking/proposal-class-modifiers" rel="noreferrer" target="_blank">https://github.com/rdking/proposal-class-modifiers</a><br>
>>>>> _______________________________________________<br>
>>>>> es-discuss mailing list<br>
>>>>> <a href="mailto:es-discuss@mozilla.org" target="_blank">es-discuss@mozilla.org</a><br>
>>>>> <a href="https://mail.mozilla.org/listinfo/es-discuss" rel="noreferrer" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
>><br>
>> _______________________________________________<br>
>> es-discuss mailing list<br>
>> <a href="mailto:es-discuss@mozilla.org" target="_blank">es-discuss@mozilla.org</a><br>
>> <a href="https://mail.mozilla.org/listinfo/es-discuss" rel="noreferrer" target="_blank">https://mail.mozilla.org/listinfo/es-discuss</a><br>
</blockquote></div>
</blockquote></div>