Closed uyeong closed 6 years ago
@lewisdiamond See https://github.com/tc39/proposal-private-fields/issues/33
The whole proposal is against everything what current JS ecosystem is built upon.
What exactly does this proposal make possible that wasn't already with private Symbol properties? Or privately scoped variables for that matter?
On a personal note, I hate it when library authors make it impossible to extend the functionality of the library as if to say "we have thought of every possible use case and deemed the impossible ones unnecessary". Us developers that use those libraries don't just hack around undocumented library internals because we have nothing better to do. I'm a big proponent of the "we're all adults here" approach. If you use undocumented features, expect your code to break with the next update and don't complain to the maintainers, but at least you got done what you had to do.
@guncha Do you expect an internal refactoring of such a library's _
-prefixed methods or fields to be a semver-major change?
IMHO, semver is used to indicate public and documented api. If a internal refactoring doesn't break any public api, don't need to change anything.
@maple3142 That sounds like a good theory, but the problem in practice is that sometimes, the direct user of the API isn't the one that incurs the cost, but rather the author of the original library and/or downstream users. I've heard from a number of library maintainers that changes in the external API can be difficult to do because of user reports of "brokenness". With nested dependency chains, where intermediate links may sometimes be unmaintained, the reports sometimes leave library authors to revert these "internal" APIs until they can work up to a semver-major change. A goal of this proposal is to give library authors a reliable mechanism for internal-only code factoring which won't break even in these sorts of cases.
But WeakMap
,Symbol
and so on doesn't actually provide hard private.
You can still hook their constructor to get private value you want.
So I think it is better to use _
prefixed methods/fields as private.
Let those who wants to hack into library can easily do it.
But library warn user about internal api won't follow semver.
@littledan Sure, maybe, you can find a few cases of people using APIs marked as private and the library maintainer reverts "private" changes that breaks downstream, though they shouldn't.
In any case, that sounds like a classic case of the survival bias.
@maple3142 The private fields are not built upon WeakMap
s, just using similar semantics. So a transpiler could use WeakMap
to mostly emulate private fields. (And of course transpilers cannot really provide hard private)
Even when using WeakMap
it would still be hard private, it could access WeakMap
directly without touching [[global]]
. Same as async/await
which is not hackable via changing Promise
.
@trotyl async/await
can be hack by modifying Promise.
Promise.prototype.then=cb=>cb('hacked')
(async ()=>'true value')().then(console.log) //hacked
(async ()=>'true value')().then(console.log)
@maple3142 This is not hacking async/await
, but the consumption of its returned Promise
, which already has nothing to do with the async
function.
Or you can hack the source, which is treated just as a normal thenable to await
.
Try hack the following:
(async function Foo () { var tmp = await 42; console.log(tmp); return tmp; })()
@littledan Refactoring _
prefixed properties in a minor version is fair game. For library authors to depend on other library's internals is highly irresponsible and they should be named and shamed, but do you agree that the math is different in the end-user case? This seems like a technical solution to a non-technical problem and because some people in the ecosystem don't know better, others will have to pay for it with the loss of flexibility.
Ultimately, the problem is that there aren't public APIs in the libraries to do things that people need to do and you're saying that this addition to the language will motivate the authors to work on those APIs while I'm saying that the tail end of those use cases is simply not going to be possible. At least now the end users can maintain their own hacks as long as they're useful since the maintainers are already spread thin and are not likely to do that.
I guess I'd personally have to resort to forking more which is still viable, but gets annoying if the issue is with a dependency of a dependency of a dependency.
I agree that this is a technical enforcement of an organizational problem, but I don't understand why that's a bad thing. We've heard from several maintainers that the phenomenon of users depending on these things and library authors not being able to make changes is real. If forking is acceptable, then it should be OK to fork to get access to private fields and methods.
IMHO current proposal is very short-sighted.
Private fields should be always somehow accessible because of:
@cztomsik This introspection is possible through decorators, see https://github.com/tc39/proposal-decorators/blob/master/friend.js for a sample. Would that be sufficient for the cases you are thinking of?
@littledan Yes, I guess that would work for ORM case (and DI frameworks) but technically, it's not introspection at all.
Also you probably don't want to decorate every private method just because of testing - that by itself doesn't happen that much but it's fairly common)
It's also common to set mocks directly to private _fields. Developers usually don't like writing tests so it has to be as easy as possible - this also explains why most of java testing is actually done in groovy which makes it easy to circumvent a lot of java type-checking.
It also wouldn't work for any kind of introspection tool (like react/angular devtools) - in these tools it's very beneficial to be able to poke into the state and sometimes even change it and check if it would fix the problem.
I'd encourage developers who are happy with _named properties to keep using them.
Technical solutions to organizational problems tend to address the symptoms (users depending on internal APIs, maintainers feeling like they can't refactor the code) while they tend to ignore the problem (lacking public APIs). Perhaps the library authors will use their newfound freedom to create the most flexible and useful APIs anyone's ever seen. Ultimately I'm saddened the "several maintainers" get to dictate what gets included in the language, regardless of user backlash.
I believe there are ways for maintainers to deprecate unsupported APIs (something they'll have to to regardless if they want to use the features from this proposal) without changing the language in irreversible ways.
For me, access modifiers are good BUT the the current private proposal isn't :
Object.getOwnPropertySymbols()
, it's for me the worst part, as we could require this for unmaintained libs on some legacy enterprise codeObject.definePrivateProperty
Exactly, I love how hackable javascript is - there should be a way to define properties visible only from within its class but they also should be accessible somehow.
ORM/serialization frameworks should not depend solely on decorators, we need some way to restore object, including its private props.
For example, let's say there's a BetterDate
class, it uses private vars and you need to deserialize it from json/binary, using framework of your choice. Now without (right) decorators this will not be possible. Not to mention if library gets unmaintained.
Stop this proposal, please.
#
looks awful
Damn, looks like a garbage! Please stop this proposal! using Symbol
is elegant than this. For me personally using #
is ugly. Maybe it's better to replace it with __
or with something which looks cleaner than #
. I think JS should be improved with functional approaches not OOP.
@aganov please avoid non constructive message. Github is a serious place not a playground for kids or trolls. Thanks.
@lifaon74 yeah, it was a bit offensive... but seriously, few hours ago I've read some article where this proposal was presented like "ready" but it's really far from that - I've raised few valid arguments and they were ignored.
I do javascript every day for last 10 years and I can tell you, this is going to change everything. From now on, it won't be "you can always hack everything" language anymore. Private fields will introduce a lot of problems. It's so huge change.
If I could, I would stop it.
Yes i totally agree with you: https://github.com/tc39/proposal-private-methods/issues/10#issuecomment-408597005
the proposal is more something from the committee and they ignore most of users feedbacks...
Same append with the /deep/ operator => they removed it so introduced something non-hackable and some problems starts to append. It will be event worse in the future: when libs will stop to be maintained the legacy code will be really hard to debug. We must fight if we're not ok with it but with constructive arguments (not like aganov)
@lifaon74 The /deep/
combinator is a Web stuff owned by WHATWG, not a JavaScript stuff handled by TC39, it's totally off-topic here.
@littledan Why private fields can't be prefixed with _
as it's now? Personally, I don't like #
, but it's still way better to have the ability to REALLY make methods/properties as private instead of using _
prefix which only warns developer "hey I'm private don't touch me!", but he can easily use it or even change it...
@svipben Code bases which want to just softly encourage others developers to treat fields or methods as private-ish can keep using _
for this purpose. #
exists alongside that for stronger guarantees. We couldn't change the semantics of _
since it's currently valid JS code and would surely break many libraries and websites that depend on the ability to use it anyway.
@lifaon74 We're working on hackability of private fields and methods with the decorators proposal. Feedback there is welcome!
@cztomsik I know it's a big change, but I think it's very valuable to give authors the chance to opt out of this hackability if they choose, using the concise #
syntax. We had a long discussion about this trade-off in the private fields repository, see https://github.com/tc39/proposal-private-fields/issues/33
@littledan thanks for explanation, that totally makes sense, we definitely need private methods in JS and ‘#’ is good proposal, waiting for Stage 4 and then browser/node.js support! 🔥
@littledan The problem is that nobody knows how useful this will actually become. For example it's now obvious people want decorators - they want it so much they were happy to transpile for years... On the other hand I don't know about anybody willing to transpile just for private fields. So maybe it's not that big issue after all.
What I want say it that it's really big change in the whole ecosystem and I would prefer holding it in stage 3 for a while. Language features are easy to add but almost impossible to remove.
@cztomsik totally agree with you, the private aspect can be done with decorators with fine control and hackable features, where the the # proposal fails to solve this (every method should be hackable, in case of absolute necessity).
For me, modifiers (ak: public, protected, private), are informations for developers ("you should not touch it") and should not stuck the user of a lib if it doesn't have choice: a modifier should always be editable (ex: with Object.defineProperty(obj, { modifier: 'protected' })), and this is exactly what symbols or the '_' prefix do: "I warn you that you should not touch this variables except if you absolutely know what's you're doing".
The bigger drawback of the # proposal, its is non hackability: we won't be able to fix old unmaintened libs (some becomes unmaintened after a few month only, because of updates or new framework), or libs with 'close' code (like some provided by: autodesk, solidworks, etc...). This will allow bad developers to completely block their code by introducing a lot of private properties (intentionally or not). Some of our choices (in libs for example) are imposed by clients, so we always need a way to hack js.
It's not clear to me how decorators can handle the private aspect. Could you say more?
@littledan a decorator like @Private, could create a get/set property on the prototype and check than the call stack is legit to access to it, or use WeakMap (with some tricks) for example. With the current language state it would be soft-private and not perfect. We could introduce better call stack access with better function.callee or with an Object.defineProperty(obj, { modifier: 'private' }). I created an experiment for chrome here: https://github.com/lifaon74/ClassHelper.
Of course for me the best of the best would be the introduction of real and hackable native modifiers (through Object.defineProperty(obj, { modifier: 'private' })) with the keywords 'private', 'protected' and 'public', because of poor performance of Decorators + get/set. This follow this topic I opened: https://github.com/tc39/proposal-class-fields/issues/15 (purely hypothetical).
The #
proposal makes impossible not only hack but also refactor.
@lifaon74 I don't think checking the call stack is a reasonable or reliable mechanism for ensuring privacy. It's not clear to me what sort of WeakMap tricks you're referring to. With respect to your alternate proposal, it seems like the issues with it were discussed extensively in the thread you linked to.
@tasogare3710
The # proposal makes impossible not only hack but also refactor.
How so?
Well as usual, its a infinite discussion with one side having a lot of arguments against (me and many others), and somes saying: "meh... no" without any concrete solution. I would appreciate concrete debate with concrete argument and proper solutions. You take one of my sentence and comment it instead of discussing the whole of what I write... I already see people quoting this vs caring the real debate... it will be reducing and its not the point of this tread.
@littledan as I sais, yes the call stack is currently not reasonable, but it could be improved (ex: with https://github.com/tc39/proposal-error-stacks), or event by returning detailed object instead of string. The best would be a full support of function.callee to have proper stack => something that could be reasonable as a tc39 proposal, and far less dangerous (with less impact) than the #.
I din't see any argument of the hackable part from the opposite side, eluding the question every-time.
@littledan You must admit than the committee is really self oriented. I get many times: "we had a discussion and we chose...[insert something] so it must be good and accepted by all". _"End of the discussion". Even if the whole community is against it ! The committee probably don't face repetitive sh*t than the average developer has to deal with: legacy code, legacy libs, bad usage of new functionalities, etc... => If you give a powerful tool to the authors (ak: private fields), you need to provide a powerful tool to the users (developers using the lib, like an Object.defineProperty or whatever), or we'll face soon code impossible to debug. Or maybe the committee is composed of only 2 mens ? because I have only seen @bakkot and @ljharb really involved in the discussion, vs hundred (at least) of developers...
@littledan I think that you need to understand the quality(or attribute) of prototype based language.
And I strongly want to say that we are not a pipe dream which only seeing things on only one side, but rather discussing real problems.
@tasogare3710 the whole point of private fields is to make it impossible to observe, hack, or alter specific runtime behavior from outside the class. That’s a critically needed feature.
@lifaon74 just because only a few of us participate in the discussion doesn’t mean there’s not full participation, and doesn’t mean the community’s opinions aren’t considered. Separately, there’s 25 people on this thread - not hundreds - and the quantity of people with an opinion doesn’t change the language constraints nor the need for this kind of feature.
@cztomsik transpiling private fields requires native WeakMap support, which requires having modern browsers - or else Airbnb would have been transpiling it for years. It’s a far more valuable feature than decorators imo (which is also a valuable feature).
@ljharb Let's finish repeating the same thing like a broken talking doll.
@tasogare3710 this is my first comment on this issue. What could i help you understand differently? Reading some of your above points, the one thing i note is that inspection by dev tools will not be hampered whatsoever, since they have superpowers - and reflection at runtime will be prevented, just like reflecting on closed-over variables.
@ljharb Decorators are so important people were using it since stage -1. If you really need private fields so bad, it's not that hard to write babel-plugin doing field name randomization, it's not really the same thing but nobody can depend on those fields/methods anymore and there is zero performance cost. Yet, for some reason, nobody is doing it.
@cztomsik randomization isn't private - that's fully public, because of Object.keys
and Object.getOwnPropertyDescriptors
etc. "private" means it's unreachable - it means you can't even observe its existence or absence. That is only possible for class instances with WeakMaps - nothing else - and thus, it's not practical for use in virtually any website (due to browser support matrices), which is also where privacy is most needed.
I think @cztomsik was just demonstrating that you could make it impossible for your lib users to use your private fields/methods. It doesn't really matter that it's not technically the same as true private fields.
@capaj of course it matters. Making something hard isn't the same as making something impossible, and true privacy requires it to be impossible.
@ljharb
this is my first comment on this issue
Of course it does not mean to say to you one person.
Many of the issues for private fields point out a number of problems that arise from adding them. So, no matter how someone shout "needed feature" those problems will not be solved.
We can not ignore the fact.
First of all, I think the necessity of the feature is strong enough to potentially override the existence of other problems. Second, can you summarize what problems exactly?
Let's all try to be polite and respectful here. If the temperature rises too much, it'll be hard for me to understand what we're talking about. I'm grateful to @tasogare3710 , @capaj , @cztomsik and others for taking the time to document their concerns here.
To me, it's an interesting data point that the unresolved concerns recently in this thread boil down to the "hard private vs soft private" debate, rather than syntax, issues specific to private methods, etc. Is that an accurate summary?
@littledan I agree with that observation. When I first heard about this spec I didn't think it was bad. Sure, syntax is kinda weird, but that's easy to get used to. The thing I didn't realize was this proposal breaks the open model of Javascript. It won't be as hackable as it is today. It will move towards java becoming a more heavyweight language. Whenever I will need to touch a private property, only way for me would be to fork the lib, change the property to a public one and then use my own fork. This happens more often than I'd like in day to day product development unfortunately.
I think it will impair existing elegance of Javascript so it should be omitted.