{"action":"created","issue":{"url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/134","repository_url":"https://api.github.com/repos/tc39/proposal-class-fields","labels_url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/134/labels{/name}","comments_url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/134/comments","events_url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/134/events","html_url":"https://github.com/tc39/proposal-class-fields/issues/134","id":364572122,"node_id":"MDU6SXNzdWUzNjQ1NzIxMjI=","number":134,"title":"[Private] Metaprogramming vs Security","user":{"login":"Igmat","id":15427508,"node_id":"MDQ6VXNlcjE1NDI3NTA4","avatar_url":"https://avatars2.githubusercontent.com/u/15427508?v=4","gravatar_id":"","url":"https://api.github.com/users/Igmat","html_url":"https://github.com/Igmat","followers_url":"https://api.github.com/users/Igmat/followers","following_url":"https://api.github.com/users/Igmat/following{/other_user}","gists_url":"https://api.github.com/users/Igmat/gists{/gist_id}","starred_url":"https://api.github.com/users/Igmat/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Igmat/subscriptions","organizations_url":"https://api.github.com/users/Igmat/orgs","repos_url":"https://api.github.com/users/Igmat/repos","events_url":"https://api.github.com/users/Igmat/events{/privacy}","received_events_url":"https://api.github.com/users/Igmat/received_events","type":"User","site_admin":false},"labels":[],"state":"closed","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":14,"created_at":"2018-09-27T17:12:17Z","updated_at":"2018-10-11T00:04:54Z","closed_at":"2018-10-10T15:03:43Z","author_association":"NONE","body":"I was kinda late to this discussion since it's already `Stage 3`, but still there is a hope that some decisions could be revisited.\r\nI've carefully read [FAQ](https://github.com/tc39/proposal-class-fields/blob/master/PRIVATE_SYNTAX_FAQ.md) and some related discussion, like #100, #106, #122 and others plus a lot of links, including other syntax proposals, that were mentioned there.\r\n\r\nProbably I missed something (there are TOO many discussions and ideas and it's non-trivial task to cover all of them, if it isn't part of your day-to-day work), but it seems that I've finally found core misunderstood between committee and community. From my point of view broken proxies (#106), when target uses `#`-privates and proxy author (probably some framework/library maintainer) can't control full class and instance lifecycle is a HUGE limitation to how we can apply metaprogramming patterns to ES real-world applications and reason why this happens is security, which `de-facto` was a hard requirement for `privates` but wasn't clearly articulated to community. _(if you're intersted I can try to find comments that lead me to such conclusion)_\r\n\r\n### `#`-syntax proposal advantages\r\n 1. **Security** :\r\n    a. I (as code author) can safely pass an object built with my class to untrusted execution context, knowing that there is no way to read or even examine its private properties\r\n    b. Nobody can apply my methods to something that isn't instance of my class if those methods use privates (somewhere it was mentioned as `brand`-check)\r\n 2. No violation of invariants defined with privates\r\n 3. Strict public API, controlled by code author without worrying that somebody will start depending on implementation details that are private\r\n\r\n### `private`-keyword syntax disadvantages\r\n - Performance: if declaration will look like `private somePrivate;` and access - `this.somePrivate`, then property lookup will become VERY difficult, untrivial and probably unsecure \r\n**OR**\r\n - Assymetry: if declaration will look like ` private somePrivate;` and access `this.#somePrivate` or `private(this).somePrivate` or whatever that not just `this.somePrivate` it will lead to one of the following:\r\n    a. Silent bugs:\r\n    ```JavaScript\r\n    class A {\r\n        private somePrivate = 1;\r\n        someMethod() {\r\n            this.somePrivate; // it's `undefined` here - which is surprising and leads to\r\n                              // incorrect behavior, runtime errors or leak of private data\r\n                              // in case if it doesn't throw `SyntaxError`\r\n        }\r\n    }\r\n    ```\r\n    b. Security breach: if example above throws `SyntaxError`, anybody outside could examine object's privates at least for their names, since `const a = new A(); a.somePrivate;` outside class definition is the same as `this.somePrivate` somewhere in class definition.\r\n\r\n---\r\nAll of the above is good motivation (assuming that security is more important) to choose `#`-syntax, even though it leads to HUGE limitation of metaprogramming using proxies (#106).\r\n\r\nInitially my motivation for writing this post was to find out the reason of such misunderstood between community (I believe I'm a part of community too) and committee.  \r\nWhile thinking about it I also tried to find simplest solution for problem described in #106, because it relates to HUGE amount of developers directly (Evan (@yyx990803), Rob (@EisenbergEffect) as maintainers of popular projects that want to use proxies for implementing proper reactivity and me as person who experiments with metaprogramming capabilities for kinda same purposes) or indirectly (developers who want/need frameworks/libraries/tooling that provides such higher-order functionality).\r\n\r\nReading issues in this repo I've found out that security pattern based on WeakMap was taken for implementing `private` proposal. But what if we'll take another approach, based on Symbols and closures.\r\n### Syntax\r\n```JavaScript\r\nclass A {\r\n    // this actually not property by itself, but rather\r\n    // property name based on Symbol and lexical scope of \r\n    // class definition\r\n    private somePrivate;\r\n    // declaring public and private property with same name \r\n    // is syntaxError, like in majority of other languages\r\n    somePrivate;\r\n    // but computed property could have same name, which also\r\n    // grants symmetry for declaring and accessing properties\r\n    // with different access levels\r\n    ['somePrivate'];\r\n\r\n    method(otherInstanceOfA) {\r\n        // to avoid surprising of developers and silent bugs,\r\n        // most intuitive syntax should just work\r\n        this.somePrivate; // resolved to private property\r\n        // since `somePrivate` actually is variable that exists\r\n        // in scope of class it could be used in such way\r\n        this[somePrivate]; // resolved to private property\r\n        // this is the only way to access public property with same name\r\n        // inside class definition - and it's ok, since any other language\r\n        // with similar concept just restrict creating public and privates\r\n        // with same name inside of one definition\r\n        this['somePrivate'] // resolved to public property\r\n\r\n        // we have to add small asymmetry for accessing privates of other object\r\n        // and it is normal, because otherInstance could be not an instance\r\n        // of this class. And even more accessing privates of other instances\r\n        // isn't something common (but obviously has use cases)\r\n        otherInstanceOfA.somePrivate; // resolved to public property\r\n        // so previous access, has least surprising behavior\r\n        // and work as expected in most cases - you can't have access to \r\n        // privates from outside, only following syntax shows that developer\r\n        // tries to do it from inside\r\n        otherInstanceOfA[somePrivate]; // resolved to private property\r\n        // and this resolved as usual\r\n        otherInstanceOfA['somePrivate']; // resolved to public property\r\n    }\r\n}\r\nconst a = new A();\r\na.somePrivate; // resolved to public property\r\na['somePrivate']; // resolved to public property\r\na[somePrivate]; // ReferenceError: somePrivate is not defined\r\nclass B extends A {\r\n    // all this will work same way as described above, without causing\r\n    // any kind of errors, because inherited methods will use\r\n    // somePrivate Symbol defined in class A, while new methods of class B\r\n    // will use somePrivate Symbol declared here\r\n    private somePrivate;\r\n    somePrivate;\r\n    ['somePrivate'];\r\n}\r\n```\r\n\r\nSuch kind of syntax doesn't have disadvantages mentioned above, because based on existing property lookup mechanism and existing closures securing.\r\n\r\nBut it doesn't have advantages of `#`-sigil based syntax, since usual Symbol could be easily found by `getOwnPropertySymbols` and/or `Proxy`.  \r\nIn order to have same security - it should be another type of Symbol. I've started to collect requirements to such kind of Symbol, but then I've found proposals that actually did it already (like this one https://github.com/zenparsing/proposal-private-symbols, I believe that @zenparsing will describe it better than I can).\r\n\r\n### Advantages\r\n - resolves #106\r\n - syntax that is known by majority of developers\r\n - could be later extended (e.g. for `protected`)\r\n - well aligned with other parts of language\r\n - better compatibility with most spread JS superset\r\n\r\n\r\n### PLEASE\r\nLet's try to have constructive discussion, because as we can see (for example in #133) there are a lot of developers that wasn't convinced by committee's arguments.  \r\nI, personally, did my best trying to find reasons behind existing proposal, and I hope that committee will do the same for community, especially after @littledan meet some of open-source maintainers in person.\r\n\r\n---\r\n### P.S.\r\n@ljharb, we all know that you hate `protected` and don't like OOP paradigm in general, so please don't try to move this topic into discussing whether or not we need it in ES."},"comment":{"url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/comments/428772946","html_url":"https://github.com/tc39/proposal-class-fields/issues/134#issuecomment-428772946","issue_url":"https://api.github.com/repos/tc39/proposal-class-fields/issues/134","id":428772946,"node_id":"MDEyOklzc3VlQ29tbWVudDQyODc3Mjk0Ng==","user":{"login":"littledan","id":189835,"node_id":"MDQ6VXNlcjE4OTgzNQ==","avatar_url":"https://avatars3.githubusercontent.com/u/189835?v=4","gravatar_id":"","url":"https://api.github.com/users/littledan","html_url":"https://github.com/littledan","followers_url":"https://api.github.com/users/littledan/followers","following_url":"https://api.github.com/users/littledan/following{/other_user}","gists_url":"https://api.github.com/users/littledan/gists{/gist_id}","starred_url":"https://api.github.com/users/littledan/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/littledan/subscriptions","organizations_url":"https://api.github.com/users/littledan/orgs","repos_url":"https://api.github.com/users/littledan/repos","events_url":"https://api.github.com/users/littledan/events{/privacy}","received_events_url":"https://api.github.com/users/littledan/received_events","type":"User","site_admin":false},"created_at":"2018-10-11T00:04:54Z","updated_at":"2018-10-11T00:04:54Z","author_association":"MEMBER","body":"1. I understand that some people don't want strong encapsulation boundaries; is that what you're referring to?\r\n2. I agree with you if you're saying that brand checking shouldn't be a core concern of the private fields proposal. I see the exceptions thrown as more of a convenience for programmers, to avoid mistakes using private fields that don't exist. (I can't stop other people from developing their own philosophies about the same language semantics.)\r\n3. To investigate the Proxy issue, we had a meeting with the framework authors who raised the concern, and we concluded, on further thought, that they will be able to make the current semantics work for them, though the situation is not optimal for them. (They didn't want anything like the capability to read the private fields of their users' classes.) See https://github.com/tc39/proposal-class-fields/issues/106#issuecomment-421556491 for more details of the discussion."}}
{"actor":{"display_login":"littledan"}}