Skip to content
This repository has been archived by the owner on Jan 25, 2022. It is now read-only.

Stop this proposal #10

Closed
uyeong opened this issue Jul 31, 2017 · 151 comments
Closed

Stop this proposal #10

uyeong opened this issue Jul 31, 2017 · 151 comments

Comments

@uyeong
Copy link

uyeong commented Jul 31, 2017

I think it will impair existing elegance of Javascript so it should be omitted.

@acidsound
Copy link

I agree. the OO is useless. and getters/setters too.

@rico345100
Copy link

I totally agree with him. In the traditional class based approach, this might be needed, so as TypeScript does. But JavaScript is not class based, it's based on prototype linked object oriented language.

"Class" in Javascript is a way different from others, and mixing original class based features into JavaScript is really bad idea. IMO, generally I don't use "private field" in JavaScript, because it doesn't needed at all.

Some of the people can say: "What if you need a encapsulation in JavaScript?"
My answer is: "You can do encapsulate your data in JavaScript without private fields."

I know, using closure to implement encapsulation and using private field is quite different, not just syntactic looks, but I just want to ask one question: "Does it really need encapsulation in JavaScript?"

If you really needed that one, I just recommend to use TypeScript. This proposal makes hard to read other people to didn't know what # means. Making readable code is also most important part of modern days, there is no programming language that uses "#" as private field in class.

If this proposal passed, later we couldn't understand what code looks like. Who knows? What kind of strange syntax will added future?

@littledan
Copy link
Member

It's true, this proposal rests on people being able to learn what # means.

Aside from the difficult of learning that # means private, and the proposition that classes are bad, do you see further disadvantages to the proposal?

@futagoza
Copy link

futagoza commented Aug 5, 2017

@littledan personally, for me it's quite easy to learn, but I simply don't like the look of the code with #, it just looks ugly, no offence m8 😄

@trotyl
Copy link

trotyl commented Aug 5, 2017

@futagoza But private fields already got stage 3, there will be # anyway, what's the meaning of just objecting # in methods?

@futagoza
Copy link

futagoza commented Aug 5, 2017

@trotyl I'm not objecting, I'm giving my opinion on the syntax look. For private values it looks fine, but once you start using it for methods as well the syntax starts to look weird to me, but if it goes through anyway because others want it, I don't mind.

@stevenvachon
Copy link

This spec causes confusion with Class#method, such as Array#includes.

@claudepache
Copy link

I simply don't like the look of the code with #, it just looks ugly

On the contrary, I find the # token of class fields very elegant; let’s accelerate this proposal!

@claudepache
Copy link

Once you have private fields, private methods and accessors are a natural extension; and if you haven’t them, people will try to emulate them using private fields. Reusing the example of the explainer:

class Counter extends HTMLElement {
    // real private field
    #xValue = 0;
   
    // emulated private accessors (not really accessors, because of syntax constraints)
    #getX = function () { return #xValue; };
    #setX = function (value) {
        this.#xValue = value; 
        window.requestAnimationFrame(this.#render.bind(this));
    };

    // emulated private method
    #clicked = function () {
        this.#setX(this.#getX() + 1);
    };

    // etc.
}

So,... it’s too late to stop the private stuff now; it had to be done with private fields.

@stevenvachon
Copy link

This is a sign that JavaScript is nearing its end. Something will overtake it, like Dart tried to do.

@tasogare3710
Copy link

I agree.
Field privacy is not based on class. It is based on abstract data type and encapsulation.

Because the design philosophy is different, these two are not necessary for javascript.

@littledan
Copy link
Member

@tasogare3710 Do you think JS has enough facilities for encapsulation already?

@littledan
Copy link
Member

@stevenvachon I never understood this idea that languages reach their end once they get features. Do you have an idea of a language that went through that kind of pattern? (C++ seems to be doing very well within its domain, for one; I think its biggest problems (undefined behavior and lack of memory safety) are not about too many features).

@stevenvachon
Copy link

@littledan it's not the features themselves, but the cryptic syntaxes that JavaScript is often limited to.

@littledan
Copy link
Member

@stevenvachon If we used @ rather than #, how bad would it be?

@tasogare3710
Copy link

@littledan If soft private is not enough, I think that other languages should be used.

In addition, # is generally a symbol representing the interned string in the language where the symbol is first class citizen.

Nobody thinks that it is a private field. I do not want to hard code reading.

@stevenvachon
Copy link

As I understood it, # was chosen because it is not currently accepted as valid syntax, where @ is.

@littledan
Copy link
Member

@ isn't currently valid syntax, but it's proposed for decorators. We discussed whether decorators and private state should "swap sigils", but ended up deciding that it should stay with decorators as @ and private as #. The hope is that people will get used to # over time. It seems like a large part of the negativity about private fields and methods is that we are using # rather than @.

@tasogare3710
Copy link

@littledan Why do we need to introduce privacy newly into the property?

Since javascript uses properties from the beginning(consistently from original javascript to currently), internally always have slots.
So, I think in than enough just to be able to freely define additional slot without introducing a new privacy.

This will have the same effect as newly introducing privacy.

@shalldie
Copy link

shalldie commented Oct 31, 2017

Yes , it should be stopped!

The # is the same as !@$%^&*()
why not use $,or user can custom it.

class Person{
    $x=0;

    $getX(){
    }
}

@tasogare3710
Copy link

The issue with Sigil is only a small misfortune.

I think that people who oppose this proposal are mainly the same thought as @rico345100.
At least I do not want Clyde and Fred to be killed by ecmascript.

@vjpr
Copy link

vjpr commented Nov 4, 2017

The # looks ridiculously bad and adds so much visual noise. It will make Javascript such an ugly-looking language. At the moment there are minimal symbols in the typical file of code, and they are visually lightweight. E.g. (){.[:<>. Compare that to #%$&* which are super busy, and confronting. You can see it just by looking.

The @ is better, but I think its such a drastic way to make the change by doing a lot of stuff all at once:

  1. introducing new behavior of hiding internals
  2. introducing new syntax, and not minor new syntax, but syntax that will dramatically change the look of all Javascript code
  3. doing it in a completely new way not seen in a modern language before by identifying private methods at the location of their usage i.e. this.#foo (sigil)

Why not start with adding the new behavior and enabling it through a comment annotation using a babel plugin like so:

// @private
foo() {}

Then people can try it out, see if they use it, if they like it, etc. FlowType could adopt it and type check using it. And this comment syntax might even be fine for a long time.

Then if its a great feature, start the discussion about the declaration syntax first. Maybe introduce private foo().

Then we could turn the private into a @, and talk about adding this.@foo.

@michelre
Copy link

michelre commented Nov 4, 2017

This should not be part of JavaScript. If people want to use this kind of thing, they should use typescript

@tasogare3710
Copy link

tasogare3710 commented Nov 4, 2017

The first thing to mention is that @littledan said "...and the proposition that classes are bad", but the class is not bad.

I agree that the # looks ridiculously bad. However, please remember everyone. Since javascript(or ecmascript) uses delegation rather than inheritance, we assert useful mechanism in class based is not necessarily not useful in prototype based.

And, i understand one thing.

People who dislike # seem to have many people in favor of this proposal unless javascript use #.

However, this issue is an issue against the private field itself for the reason "javascript does not need a private field".

I have a suggestion. How about separating Sigil issue from this issue?

@bakkot
Copy link
Contributor

bakkot commented Nov 4, 2017

@tasogare3710, we've heard from a lot of people, especially library authors and frameworks like node, that they do need private fields.

Closures don't provide the same sort of encapsulation - they don't provide a good way for many objects to be able to examine each other's state without exposing that state to the world.

For example, it's very difficult to use closures to implement something like

class Point {
  #x;
  #y;
  equals(p) {
    return this.#x === p.#x && this.#y === p.#y;
  }
  // other methods
}

So, while I understand that you have not had a need for private fields, that's not enough to establish that the language doesn't need them, especially when we've heard from a lot of people that they really do.

@vjpr
Copy link

vjpr commented Nov 4, 2017

we've heard from a lot of people, especially library authors and frameworks like node, that they do need private fields.

What makes JS nice is that it is hackable and monkey-patchable. You can poke around. There are so many internal node things that I've used and monkey-patched over the years that are absolutely necessary. And sometimes its good to be able to look around just for debugging purposes. E.g. inspecting the internal state of a library you are using.

I think if you are a library author, perhaps you have different priorities than a consumer. If there is a bug, you already have the project checked-out, and you can fix your own library, or you know potential workarounds. If you are consuming a library, you just want things to work, monkey-patch if necessary, and move on. Making everything private assumes that there are never bugs that can only be debugged by inspecting the internals, but every library has bugs. And since there are so many toolchains involved these days, its not so easy to just git clone, npm link, and inspect, and usually npm dists are not bundled with sources.

@bakkot
Copy link
Contributor

bakkot commented Nov 5, 2017

@vjpr, that's never been entirely true - you can't poke around inside of closed-over variables (except with debugging tools, of course, but debugging tools will be just as free to modify private fields as they are to modify closed-over variables). Indeed, the sort of privacy provided by closures has very much served as a model for private fields.

That aside, this is the reflection vs encapsulation debate. It's one the committee is very aware of, but having considered it at length we came down on the side of encapsulation. There are of course major benefits to allowing reflection, which we all are familiar with, but there are also real costs. (And I think that's something other languages have been finding as well.)

@vjpr
Copy link

vjpr commented Nov 5, 2017

@bakkot

class Runner {
  #items
  run() { this.#items.map(x => this.#foo(x)) }
  #foo() { console.log(x.foo) }
}
const runner = new Runner
console.log(runner.#items)

Every dev would make items private. Now if the dev wants to inspect items during development, they need to add a getter. Then if they think the user should have access in prod they must decide whether to add a getter. It starts to make JS feel like Java.

There are two cases:

  • I want to reliably indicate that something is private.
    • Everyone would welcome this, and it would be great. For IDEs, tooling (Flow), testing, stack trace messages, etc.
  • I want to prevent the user accessing internals.
    • No developer would ever ask for this. If they did, they would be saying "its hard to tell what is private and what is not". No one would be saying: "I'm addicted to using library internals, I know I shouldn't but I just can't stop."

I've read the faq, and a bunch of the discussion issues here. I think library developers requests are being prioritized over users, and there are more users than library developers, and as I mentioned above they have different priorities.

Anyway, if it has to happen, then please use the @ instead. BTW, what is the likelihood of things changing at this point?

@tasogare3710
Copy link

@bakkot My opinion is consistent.

If you have problems with the following code, you should use other languages instead of javascript.

var private_fields = new WeakMap
class Point {
  constructor(x, y) {
    private_fields.set(this, {x, y})
  }

  equals(p) {
    var {x: my_x, y: my_y} = private_fields.get(this)
    var {x, y} = private_fields.get(p)
    return my_x === x && my_y === y
  }
}

var __x__ = Symbol("x")
var __y__ = Symbol("y")

class Point2 {
  constructor(x, y) {
    this[__x__] = x
    this[__y__] = y
  }

  equals(p) {
    return this[__x__] === p[__x__] && this[__y__] === p[__y__]
  }
}

So, while I understand that you have not had a need for private fields, that's not enough to establish that the language doesn't need them, especially when we've heard from a lot of people that they really do.

Delegation does not require other different objects in advance to make a new object.

However, private fields currently have classes only. This leads to the wrong design in javascript which is a prototype based OOP.

The wrong design is to give the illusion that javascript must prepare another different objects before creating a new object. It is a characteristic of inheritance, not delegation.

In javascript(and prototype based OOP), constructor functions and class constructors(these are instance creations) must be used to remove boilerplate code for initialization.

There is "one-of-a-kind objects" created by other methods in javascript.

function SameKindObject() {
    // A lots of initializations.
    // However, it has common properties.
}

var common1 = new SameKindObject
var common2 = new SameKindObject
var common3 = new SameKindObject

// this is "one-of-a-kind"
var not_common = {
    // include unique properties
}

Even though allow private fields, you can not have private unique properties in "one-of-a-kind objects" in the current proposal. This part has room for discussion.

Btw, is inspection included in reflection? Javascript is an easy to inspect by nature(for-in and json etc).

Although we should not test private fields, inspection is essential for logging, debugging and externalization etc.

However, private fields may make to these difficulties.

@bakkot
Copy link
Contributor

bakkot commented Nov 5, 2017

@vjpr

Now if the dev wants to inspect items during development, they need to add a getter.

Or use development tools, or for that matter just make it public.

Then if they think the user should have access in prod they must decide whether to add a getter.

Again, or just make it public. I don't understand why you'd make something private which you wanted users to have access to.

I want to prevent the user accessing internals. No developer would ever ask for this. If they did, they would be saying "its hard to tell what is private and what is not".

Many, many developers have asked for this. This is precisely the hard-private vs soft-private debate.

They're not saying "it's hard to tell what is private". They're saying "if this is not actually private, it's part of my public API, and my users will read and change it regardless of how much I intended them not to, and that makes my life much more difficult".

I think library developers requests are being prioritized over users, and there are more users than library developers, and as I mentioned above they have different priorities.

It is part of our mandate to balance different needs, yes.

But most users don't need to access internal state of libraries, I think; it's only a fairly small subset who want this. And to a large extent the needs of library authors are the needs of users, because users need those library authors to keep maintaining their libraries.

Anyway, if it has to happen, then please use the @ instead.

We discussed it at some length a while ago and decided to go with the current setup. We might revisit if there's some reason to, but it would have to be something more than "I don't like it".

BTW, what is the likelihood of things changing at this point?

If something comes up which we hadn't thought about, reasonably high. It's very unlikely that we will change anything purely on the basis of things we've already discussed at length, though, like hard vs soft private.

@tasogare3710

If you have problems with the following code, you should use other languages instead of javascript

This is not the opinion of the committee. WeakMaps work for this, but are non-obvious, somewhat awkward to use, and error-prone.

Even though allow private fields, you can not have private unique properties in "one-of-a-kind objects" in the current proposal. This part has room for discussion.

Yes, this is something we've thought about. We may well add them later, just not as a part of this proposal. However, this use case is already reasonably well met by closures, I think:

var priv = 1;
var obj = {
  pub: 2;
  method() {
    return this.pub + priv;
  }
};

Btw, is inspection included in reflection?

Yes.

Javascript is an easy to inspect by nature

Not always. There has never been a way, as part of the language, to inspect the variables a function closes over.

Although we should not test private fields, inspection is essential for logging, debugging and externalization etc.

Again, this is the reflection vs encapsulation debate, which we've talked about a great deal. These are points which have been brought up (many times) before, and even taking them into account, we still felt that having a reasonably easy way to provide encapsulation was important.

That said, logging and debugging can be accomplished by development tools, which can access whatever they want, including private fields. And I'm not sure what you mean by externalization; there are a couple of ways I normally encounter that term, but none of them seem like they'd really be impeded by private fields.

In any case, if the developer doesn't actually want encapsulation, they shouldn't use private fields. There is a fundamental conflict between reflection and encapsulation; if the benefits of reflection (including inspection) to a specific developer outweigh the benefits of encapsulation, then just don't use private fields. That's not a sufficiently good reason to deny them to everyone.

@TongtongGitHub
Copy link

The changes about JS recently really give me a strong reason to learn about TS. The stupid commitee push me out of JS!!!! People will vote by code.

@arogg
Copy link

arogg commented Oct 14, 2018

Why did they favor the # syntax instead of breaking backward compatibility?
Few people will use # because of how bad it reads. If one can judge it one will notice this by reading the code in this thread.
What do I care. I won't use this feature.
I use Typescript. Maybe it will get an option to compile to # syntax. And if not, fine.
Maybe tc39 will be forced to revise the feature down the road, because of its unpopularity, who knows.

@zilong-thu
Copy link

I Don't think JavaScript need private Class fields to implement private variables with closure functions.

@ljharb
Copy link
Member

ljharb commented Dec 27, 2018

For instances, it does, since the only other way to do it is with closed-over WeakMaps.

@ScottGibsonEmpire

This comment has been minimized.

@iiw
Copy link

iiw commented Feb 1, 2019

Good feature, I'd like it (add to eslint ban rules)

@nurbek-ab
Copy link

I hope it will be abandoned. If not, well, time to learn some new programming language because I don't want to mess with this ugly syntax.

@houd1ni
Copy link

houd1ni commented Mar 20, 2019

Also +1 to stop it, 'cause of rejecting this: #8

UPD: To not to make another comment: My reasons are primary about wheel-reinventing synthax. Backwards compatibility could be avoided by not using it without transpiler in new code.

With the same efforts, we could just do i.e. %valName = 42 instead of const and №valName = 43 instead of let.

About public fields: it's not actually a problem to hide it, because of the fact, that it needs js engines work. If one prefers small work with engines and then headache throughout js coding, I don't share his idea.

@slikts
Copy link

slikts commented Mar 20, 2019

The first two items in the FAQ explain why that syntax isn't used. Your +1s are just noise if you're not actually addressing the reasons.

@fresheneesz
Copy link

Maybe its time to go back to the drawing board if your goals require such bizarre and unjavascripty syntax in order to "achieve" them. Maybe the goals are too stringent. Maybe javascript simply can't be fixed without breaking backwards compatibility. Honestly, the last point should not be surprising based on how long javascript has maintained backwards compatibility. You can't cater to old code forever. This proposal is a mess.

@fresheneesz
Copy link

fresheneesz commented Jun 13, 2019

This proposal is:
Unacceptable

@stevenvachon
Copy link

I recently created scrolling-menu using private methods/fields and I was surprised at how much I did like it, despite my previous complaints. Check it out to see for yourself.

@mathiasbynens
Copy link
Member

Was it not Katy Perry who once so wisely said

I used a private field and I liked it

@cztomsik
Copy link

Was it not Katy Perry who once so wisely said

I used a private field and I liked it

Maybe before she learnt how to javascript and understood there's no need for them.

Seriously, I'm doing javascript almost every day for the last 12 ys and I've never found myself in the situation like "OMG, I wish javascript had private fields, it would make my life so much easier" and I've been talking to many people in the last few months about this and they actually agree with this.

I don't know who you are talking to and why do you think that this is such a great idea (that it's already in stage3) but there's certainly a lot of people who are not active here nor they are blogging on medium and yet if you tell them about this proposal they will just facepalm and say, yeah, javascript :-/

And they don't understand a lot of other of your work, for example exponential operator - when you explain that it's just sugar for Math.pow() they look really puzzled and don't understand the motivation for such thing at all (and I don't either). And yeah, we might be wrong, there might be valid use-cases but it would be 1000% better if you've shown such use-cases in the proposal because otherwise it looks like you're extending the language just for the sake of it.

@asyncLiz
Copy link

Don't forget that class is just syntactic sugar for prototyping. Extending the language and adding syntactic sugar is not a bad thing if it improves the development experience and maintainability of code, and there's precedence for it.

There are plenty of valid use cases for private fields. The common convention right now is to use one or two underscores (_property or __property) to indicate that a field is "private" and shouldn't be touched externally. The code may not work properly is the properties or methods are invoked or modified externally.

Private fields give developers control over encapsulating what logic of their code is exposed for consumption. It's no different than private fields in Java, C#, or any other language. When JS started, it was not used as a full featured language. Now that JS apps are becoming more and more complex, missing features such as traditional classes and private fields become more and more useful.

@cztomsik
Copy link

cztomsik commented Jun 14, 2019 via email

@ljharb
Copy link
Member

ljharb commented Jun 14, 2019

@cztomsik if they're accessible or observable from outside the class, you're treating them as public. If you want them to be private, they actually have to be private.

Discussions of other proposals belong on those proposal repos.

@stevenvachon
Copy link

JavaScript already has private methods. This proposal is merely syntactic sugar. The reasons for its syntax has been explained and there're no better alternatives. See my link above -- it's actually not ugly.

@fresheneesz
Copy link

fresheneesz commented Jun 15, 2019

it's actually not ugly.

We all know there's reasons this syntax has been chosen. But don't pretend sigils aren't Ugly AF. Case in point.

@cztomsik
Copy link

@ljharb developers are not dumb - having a gun doesn't imply shooting yourself.

@stevenvachon it's syntax sugar for something you actually don't want, private methods are impossible to test, monkey-patch and introspection devtools will be harder too (if possible at all).

I've actually seen your repo and my points still apply - try to write some tests and you'll notice the difference.

There is a reason why people are sometimes unit-testing "private" methods. There are also valid uses for monkey-patching (polyfills & zone.js just to name a few).

@ljharb
Copy link
Member

ljharb commented Jun 15, 2019

@cztomsik if that’s the metaphor you want to use, then actual statistics say that yes, it does imply exactly that, far more often than is accepted - but let’s plead stay away from that metaphor here.

Private things are impossible to test because private things should not be tested - test the public api and behavior/semantics, and only that. Devtools have superpowers, so nothing is impossible for them, including introspecting private fields.

There’s no need to runtime monkeypatch; that’s what forking is for.

@stevenvachon
Copy link

I've actually seen your repo and my points still apply - try to write some tests and you'll notice the difference.

Um, there are tests.

@c69
Copy link

c69 commented Jun 15, 2019

i think it would make a lot of sense to actually list libraries (or related proposals) where authors "asked for private properties and methods".

Because right now (even by reading meeting notes) - there is no transparency on who and why want this.. And maybe if the case is compelling for wider audience, "twitter" auditory (like myself) will stop over-reacting.

p.s.: this proposal also pushes 4 separate things at the same time

  • shared-but-hard private via weakmaps (correct me if im wrong)
  • namespacing syntax with sigil
  • sigil # actually becomes a new significant character (and that feels like very non-frugal use for it).
  • and "this has been discussed many times. there is no point in arguing. resistance is futile. this WILL become a part of standard you like it or not" attitude.. And because we already have parts of ES6 that are largely unused (TCO, Proxies) and or feel half-baked (Sets/Maps, Iterators) and pushing for more divisive changes does not add to positive atmosphere.

I think, most people would actually accept private fields, if more conventional syntax was proposed and there were more motivational examples.

@cztomsik
Copy link

Private things are impossible to test because private things should not be tested - test the public api and behavior/semantics, and only that.

I'm not writing tests to make somebody happy, I'm writing tests to avoid bugs and testing private method is sometimes the most simplest and straightforward way to cover something - or at least some critical part. What you say is naive and very disconnected from reality. Time spent for tests is time which could be used for features, and so that's why people do it and why it's totally fine. What you propose is nice in theory but often a lot of extra work (with no real benefit) in practice.

Devtools have superpowers, so nothing is impossible for them, including introspecting private fields.

Ok then, let's say I want to do such tool - how can I do it? Where's some API for this? Can I call it from user-space? Or do I have to fork V8?

There’s no need to runtime monkeypatch; that’s what forking is for.

I'd agree that it's something which should be avoided, but you're wrong that there's no need, there is - and polyfills & zone.js (mentioning again, for some reason you've ignored those) are exactly that, react-hot-loader does some nasty shit too and that's done by react core devs (who arguably could bake some support there but they didn't).

@stevenvachon In that case, I'm sorry I had to miss them, but my points are still valid.

@fresheneesz
Copy link

resistance is futile

This is my biggest problem with this. It seems like these people don't give two craps about who hates this proposal or who want it. THEY want it and that's all that matters. They don't seem to care to show us evidence that the javascript community wants this. That attitude is toxic and doesn't belong in a standards-making process. The burden of proof is on the proposers to show us that this is wanted by the community. Telling us "there's no other way to do this" is simply not relevant.

@tc39 tc39 locked as too heated and limited conversation to collaborators Jun 17, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests