-
Notifications
You must be signed in to change notification settings - Fork 25
Configurable vs nonconfigurable properties #36
Comments
@erights I'd be interested to hear your thoughts on this. |
This syntax is declarative, so it should result in something with declarative semantics, in the sense of obeying an eternal invariant rather than a momentary invariant. If the properties are non-configurable, then they will continue to exist with the same meaning for the lifetime of that object. If they are configurable, then their continued existence is an imperative matter, not a declarative one. We already have a perfectly fine syntax for imperatively creating properties that may disappear. This all reminds me of a similar argument we had a long time ago: Do we need both Now that we've lived with |
Doesn't your argument also apply to the |
Sure. If we had a choice about what this means I would take on that argument. We don't. |
Which raises the question of whether the principle you give in that post is more important than consistency with the rest of the language's declarative property/method syntax. |
Sure. This is a valid question. |
After having lived with let and const for a while now, I'm convinced that the only practical result is a burden of useless choice. |
The other consistency we need to pay attention to is between declarative class properties and declarative private fields. Obviously there are some necessary differences between them. But we should avoid gratuitous differences when we can. Private fields exist stably during the lifetime of the object. |
Apologies, the previous comment is nether here nor there with regard to public class fields. I've been doing quite a lot of programming lately where the let vs. const thing has been a factor. Are static public fields supposed to be non-configurable as well? |
Although I can see a few reasons why the case for non-configurable static properties is weaker, I still think that they should be non-configurable. Btw, on terminology, I try to be careful to say "public property" and "private field". To avoid confusion, I think we should avoid terms like "public field". |
while i hardly get what this is about, it is clearly still the root of my problem. with reference to this proposal loganfsmyth/babel-plugin-transform-decorators-legacy#44 @loganfsmyth argued that a decorator should set configurable to false. this causes problems in the aurelia framework since the properties cannot be observed anymore by adding getters/setter, but must fall back to dirty checking. so, either
thoughts? |
👍 |
@doktordirk I don't think configurability affects Aurelia's use case here. Presumably, the Aurelia decorator would transform the field declaration into a getter/setter pair before it's actually defined on an instance, so there would be no Set of a nonconfigurable property. |
@littledan aurelia isn't (by default) using decorators for this, but only when bootstrapping the view-model's view. one can add an observable decorator though. That some nuisance but does fix the problem. it still highlights though that using configurable:false has side effects. ps: i might mention that this (currently?) is not an issue with the typescript implementation of decorators. |
@doktordirk Is that because TypeScript defines configurable properties (with Set)? |
TypeScript uses http://www.typescriptlang.org/play/index.html#src=class%20C%20%7B%0A%09f%20%3D%2042%3B%0A%7D |
What's the verdict on this? |
At the recent TC39 meeting, we didn't revisit enumerability; the current proposal still uses enumerable/configurable: true. |
Configurable. It follows from orthogonality.
…On May 28, 2017 4:39 AM, "Wesley Overdijk" ***@***.***> wrote:
What's the verdict on this?
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#36 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/AAQtzFuFGsKw2Rkq8wcb0cYS9s4PXLC7ks5r-VzcgaJpZM4IFFFN>
.
|
@littledan No, the current spec text uses configurable: false. @erights The orthogonal classes proposal is still (unless something has changed in the last meeting that I missed) very controversial, and I don't think it should be used as justification for a change in this proposal. I personally do not agree that each aspect is orthogonal. I believe the most common case should be the one with the simplest syntax, and the number of truly nonsensical combinations undermines the basic orthogonality principle. |
I suspect that @erights wasn't referring to the Orthogonal Class proposal proposal, but rather to the overall orthogonality of the ES specification. Issues of property configurability defaults (for classes and elsewhere) were deeply debated during the development of ES6. We reach certain conclusions based upon analyzing the existing precedents of the language and who to most consistently extend those precedents to encompass new features. Roughly here is what we concluded:
These rules should be followed for new class features. Class fields should default to configurable: true, writable: true. Not doing so will just create consistency WTFs that make the language harder to learn and use. It's fine to in the future to consider adding new kinds of class declarations (via new keywords, decorators, etc.) that facilitate define classes with deferent defaults. |
@allenwb wrote:
You meant configurable: false, writable: true, right? |
@erights See Step 16 of https://tc39.github.io/ecma262/#sec-runtime-semantics-classdefinitionevaluation and Step 5a of https://tc39.github.io/ecma262/#sec-makeconstructor |
I'll be honest I don't really see the point of public fields if it just turns this: class Counter {
constructor() {
this.x = 0
}
increment() {
this.x += 1
}
} Into this: class Counter {
x = 0;
increment() {
this.x += 1
}
} Having two different syntaxes for pretty much the same thing when half the time you'll be adding additional properties in the constructor anyway like this: class Task {
ready = false;
constructor(initializer) {
this.initializer = initializer
}
...
} seems a bit pointless, but if the fields are non-configurable then at least you can guarantee that there's actually a semantic difference between these three definitions, which personally I'd expect given that public fields feel like they should be a guarantee of some field: class Task {
ready = false; // Guaranteed to exist
initializer; // Guaranteed to exist as well
constructor(initializer) {
this.initializer = initializer
}
}
class Task {
ready = false; // Guaranteed to exist
constructor(initializer) {
this.initializer = initializer // But without the field declaration this can't be certain to exist
// so 'initializer' in someTask can't be relied upon to detect capabilities
}
}
class Task {
constructor(initializer) {
this.ready = false
this.initializer = initializer
}
} A nice bonus with non-configurable fields is that if there's ever a proposal to add some form of typing then there won't be any issue with class fields having non-existent properties. e.g. class Point {
// Syntax similar to TypeScript just for sake of exposition
x: Number = 0; // Guaranteed to both exist and be a number
y: Number = 0;
constructor(x, y) {
this.x = x
this.y = y
}
} |
There are so many things that can go wrong here and expose fields not existing, or being in different states, besides deleting them; I don't have much confidence that if we tweaked one thing we'd be able to have guaranteed stable object shapes. This includes:
Anyway, I think decorators on fields will be a good way to expose nonconfigurability, nonenumerability, etc. |
To me, the issue hinges on orthogonality. In the Orthogonal Classes framework, placement (class, prototype, instance) is orthogonal from visibility and type. If we wish to preserve this as a framework for growth, then it implies configurability. Non-configurability would be a non-orthogonal surprise. The compromise that we arrived at in the state of this CL, aside from configurability, can still be rationalized as being within the Orthogonal Classes framework. However, frankly, it also makes further steps towards Orthogonal Classes less likely because there's still no keyword for overriding default placement in order to place something on an instance (e.g., "own") or a prototype (e.g., "shared"). The current CL, again aside from configurability, can also be rationalized as being simply a starting point for going forward without any Orthogonal Classes framework and accomplishing these overrides with annotations. If we now expect the second is more likely, then I agree with @Jamesernator . He exactly states my position prior to Orthogonal Classes:
As for @littledan 's points:
Yes, this breaks a hard guarantee. But it is mostly-statically apparent in the code of the constructor whether
Although efficiency of the implementation might be a benefit, the main benefit is software engineering -- making the program's behavior more predicable, and more likely to stay within the assumptions the programmer made when they wrote this code.
These unfortunate edge cases do further weaken the reliability of the programmer's reasoning. But by itself does not justify taking further unnecessary steps to make that reasoning even less reliable.
Yes, this is unfortunate. This is why, for a long time, I advocated that the initialization should be written in the body of the constructor, so that constructor arguments would be visible from the initialization expression. Alas, I think I made a mistake conceding on this point. But I think this mistake is unrecoverable. Having conceded, I am sure we could never get consensus for moving these declarations back into the constructor. So, again, we lack a hard guarantee. But partially initialized instances that escape are monsters anyway. If the programmer can get reliable behaviors from fully initialized instances under stable prototype chains, a program's behaviors are less likely to violate its author's expectations.
I agree it is an adequate way, and therefore either decision here is acceptable. With decorators, we can survive getting the defaults wrong. But we should still try to design good defaults. |
@erights Are you saying that given the current direction of class syntax, you are not in favor of "public" field declarations? Having recently converted some TypeScript code to JS (with public fields), I agree with @Jamesernator
Without a type system to worry about, it doesn't carry the weight. |
No, I am saying:
|
I think that presumes that even if they are nonconfigurable and not heading towards orthogonality, that they lack value - a statement I disagree with. While I like the philosophy of orthogonality, I prefer configurability in any scenario, and I also think fields (private and public) are hugely important as-is on their own merits. |
@erights I don't think orthogonality is all-or-nothing. My hope is that soon, we will have public and private instance and static fields, and public and private shared methods, static methods, and shared/static accessors. I've written a draft specification of this idea, though I still have to break it out into a proposal, etc, which I hope to do over the next week or two. |
The current document defines properties that are nonconfigurable, based on a change by @michaelficarra . I wanted to open this bug to discuss whether they should be configurable or nonconfigurable, and lay out the points in both directions.
Pro
Con
Thoughts? @erights @domenic @dherman @allenwb @zenparsing
The text was updated successfully, but these errors were encountered: