Comments (21)
- It would be useful to identify invalid private field references with static analysis. This won't be possible if decorators can create private fields at runtime.
This is still preserved since the PrivateName would be anonymous as mentioned in the paragraph. #
syntax would not be able to use those anonymous fields.
from proposal-decorators.
Thanks for the responses. I've edited the original issue to remove the static analysis property.
I think this would be useful for a number of frameworks. The side effect would usually be on the setter, rather than the getter, to queue re-rendering if it is overwritten.
I'm not sure I agree about this -- it seems like if a framework is able to observe all changes to a property/field on a user-provided class, then the field is part of the class's public API. In my opinion, it's important to preserve the invariant that a class can safely change the value of its private fields without worrying about "spooky action at a distance" (side-effects from outside the class). In other words, I think the decorator shouldn't be able to modify the descriptor after it's created, although it can sometimes transform the initial value.
from proposal-decorators.
I must be missing something fundamental. How is it possible for decorators to break the private state encapsulation? You'd have to actual modify the source code of the class in question to add the decorator. But if you do that, you might as well just remove the #
sign. "Encapsulation" doesn't mean robustness against people editing the class definition.
from proposal-decorators.
I'd be fine to say, private class elements don't get decorated the first time around. In this repo, I'm providing a "maximal" proposal, analogous to @erights' earlier orthogonal class framework; it's not to say that this all needs to happen right now, or that it will all eventually happen.
- This proposal doesn't let decorators mess with the lexical bindings made by private field or method declarations, only change what they point to (e.g., a private field to a private accessor).
- As for where I got these use cases,
- Sometimes classes are pretty big and take time to refactor, but I agree that this case is more marginal than the other one.
- I think this would be useful for a number of frameworks. The side effect would usually be on the setter, rather than the getter, to queue re-rendering if it is overwritten. cc @diervo @wycats
- The intention is to preserve this property.
from proposal-decorators.
"spooky action at a distance"
Spooky action at a distance is sort of the entire point of decorators. If it's not OK for private fields, why is it OK for public fields? Maybe it really isn't OK for either; I have heard this objection in the past with respect to public decorators.
In other words, I think the decorator shouldn't be able to modify the descriptor after it's created, although it can sometimes transform the initial value.
Even if you're explicitly annotating that particular private field declaration to a decorator?
What changes do you think should be possible to the initial value?
from proposal-decorators.
If it's not OK for private fields, why is it OK for public fields?
My impression of decorators on public fields is that they're roughly syntactic sugar for something that would be possible to do after the declaration anyway by mutating the prototype. On the other hand, private fields are something completely internal to the class, and (in the absence of decorators) they are completely unobservable outside of the class. So I think it makes sense to allow decorators only on public fields, because external functions can only access public state.
What changes do you think should be possible to the initial value?
Disclaimer: I haven't followed past decorator proposals very closely. My view of what a decorator would be able to do is similar to what a python decorator can do (i.e. it's just a higher-order function that gets called at declaration time on the original value, without having access to binding info).
So with code like this:
class A {
@foo
#bar() { baz(); }
@foo
set #qux(value) { baz(); return value; }
}
The private method #bar
would be given a value of foo(function() { baz(); })
, and the private field #qux
would have a setter with the with the function foo(function(value) { baz(); return value; })
.
I realize this model of decorators is less powerful than the version where they have access to the descriptor, and it's fairly different from the current decorators proposal, so feel free to ignore it. I'm more sure about the first point (that decorators shouldn't have access to private state) than I am about what they could do with the binding if they did have access.
from proposal-decorators.
My impression of decorators on public fields is that they're roughly syntactic sugar for something that would be possible to do after the declaration anyway by mutating the prototype
With fields, this is no longer true. Decorators can add fields with initializers, and there's purposely no reflection API for doing the same.
it's just a higher-order function that gets called at declaration time on the original value, without having access to binding info
This is an interesting idea. The current decorators proposal is far more general, to allow things like a "non-enumerable" decorator, but we could provide a more restricted API for private methods.
from proposal-decorators.
I definitely agree that private and public fields are fundamentally different, and that there are things that make sense for public fields that do not for private fields.
Since private fields do not have the same descriptor properties - eg, enumerability is irrelevant, they're always writable, etc - I wouldn't expect a decorator to be able to do anything except transform the initial value.
from proposal-decorators.
In this proposal, a decorator could create a non-writable private field.
from proposal-decorators.
That's surprising to me; how would I make a private field nonwritable without a decorator?
from proposal-decorators.
@ljharb how is that different from public fields. In general, we haven't added any specific modifiers to public or private fields, with the assumption that for now, people can use decorators to customize the behavior of these fields.
If particular decorators become popular, we can look into adding first-class modifiers to the language, no?
from proposal-decorators.
You could only do it with a decorator. This is just like how we only have non-enumerable fields or enumerable methods with a decorator.
function nonwritable(element) {
element.descriptor.writable = false;
return element;
}
from proposal-decorators.
@littledan That's a decorator; I'm asking how I'd do it without decorators - as far as I'm aware I can replicate everything a decorator can do on public fields without them; it's just at a different time and less elegantly.
@wycats I'm not asking for a first-class modifier; I have Object.defineProperty already - I'm saying that I expect decorators not to be strictly required for any functionality like nonwritability.
from proposal-decorators.
@ljharb By design, in this proposal, decorators are the only API for a couple things--adding fields and doing reflection on private things. I'd rather not introduce even more imperative APIs for these.
from proposal-decorators.
@domenic that's true I think of the field being decorated, but not necessarily as true of the decorator that I added on #x being able to access a different #y.
from proposal-decorators.
Sure it is. You still had to get access to the class body. You could remove the # from y just as easily as from x.
from proposal-decorators.
I'm saying that allowing decorators on private fields violates the following invariants:
- Getting or setting a private field in a class is unobservable outside the class.
- The value of a field cannot be modified except by using an explicit assignment in the class.
- Refactoring a class to add private fields, remove private fields, or change the behavior of existing private fields is unobservable outside the class.
I think these invariants would be useful because they would make it easier to refactor classes. With these invariants present, the API of a class would only be defined by its public fields/methods, and the internal representation could change without affecting consumers. In my opinion, being able to define an opaque internal representation of a value is the main use case for private fields.
@domenic It's true that the invariants would still apply anyway for classes without decorators, so adding a decorator could be considered an opt-out of the invariants. However, the ability to do this seems like it would be encouraging poor class design. I suppose my argument isn't that the existence of the feature breaks encapsulation -- it's more that we shouldn't encourage users to shoot themselves in the foot by exposing internal state to external decorators.
from proposal-decorators.
@domenic oh totally, but if I want #y
to be private, I may not realize that adding a decorator onto #x
would expose #y
. If only a class decorator can access all private fields, and a private field decorator can only access its own private field, then my comments indeed don't apply.
from proposal-decorators.
Any more thoughts on this issue? I still that decorator access to private class elements is very useful. For one, it seems like a better solution at least to start than any of the protected
/friend
modifiers I've seen proposed. For one, this allows decorators like @testable
to expose the entire class to tests.
The logic for exposure is, if you decorate a class element, then you're giving that decorator access to the class element, and if you decorate the class, you're giving the decorator access to the whole class. Logically, if you decorate an element, you're in the class. I don't think decorators are a way of opting out of those invariants you're listing; it's just that decorators are considered inside for the purpose of the the invariants.
It seems that this is a big unsettled topic, and I failed to bring it up at the last TC39 meeting, so I'll have it as part of the presentation for the next one.
from proposal-decorators.
I presented on this topic at the January 2018 TC39 meeting, explaining the logic for what encapsulation means with respect to decorated private fields: That the decorator is considered "part of the class". I didn't hear any objections in the question period.
Offline, @concavelenz expressed some hesitation about exposing private names in decorators as well. He and @wycats discussed this issue further. My understanding is that the concern is not fatal; maybe one of the two can elaborate here.
from proposal-decorators.
We've discussed this question at additional TC39 meetings since January. I believe we have concluded that decorators should be able to see private class elements--that the use cases are significant enough to justify the downsides stated in this thread.
from proposal-decorators.
Related Issues (20)
- Stage 3 allow decorators to generate PJOs HOT 1
- Timeline / proposal for extensions? HOT 8
- Using accessors makes code less clean and readable HOT 21
- Counterintuative ordering when using `accessor` in combination with `init` methods HOT 37
- Can't dynamically set private field in initializer HOT 17
- Context.private doesn't seem to support group accessor HOT 1
- Support changing the backing field used by auto-accessors HOT 2
- Towards stage 4 HOT 14
- Field and Accessor initializers should run after the field/accessor has been defined HOT 12
- Stage 3 cannot access the class for static method decorator HOT 3
- Idea: syntax for decorator composition. HOT 3
- How to exclude methods from class decorator HOT 2
- Add target class to the context HOT 6
- Order of execution HOT 3
- It isn't clear when `addInitializer` functions are called on class decorator HOT 2
- feature request (separate proposal?): `context.addPostInitializer()` HOT 18
- Readme text and types are outdated against actual spec HOT 2
- Field decorator initializer should support configurable field HOT 8
- Was there a purpose for non-lexical ordering of decorator applications? HOT 2
- Write upgrade guide for previous iterations to Stage 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from proposal-decorators.