Hacker News new | past | comments | ask | show | jobs | submit login
V8 release v7.2 (v8.dev)
159 points by stablemap on Dec 18, 2018 | hide | past | favorite | 134 comments



> V8 v7.2 adds support for public class [1] fields. Support for private class [2] fields is planned for a future V8 release.

For those who don't know private class fields add the weird "#" character for defining them inside the `class {}` block.

    class IncreasingCounter {
       #count = 0;
       get value() {
           console.log('Getting the current value!');
           return this.#count;
       }
       increment() {
           this.#count++;
       }
    }
This looks way worse than having what TypeScript did by introducing `public` / `private` keywords. Is there any body which votes for es-next features such as this one? I wonder how the "#" private field popped up in Chrome specs.

1 : https://developers.google.com/web/updates/2018/12/class-fiel...

2 : https://developers.google.com/web/updates/2018/12/class-fiel...


If you think that the # syntax for private fields needs to be improved, then go to JS Committee's GitHub Issues and give feedback about it:

https://github.com/tc39/proposal-class-fields/issues

There's at least three specifically about the #:

https://github.com/tc39/proposal-class-fields/issues/177

https://github.com/tc39/proposal-class-fields/issues/149

https://github.com/tc39/proposal-class-fields/issues/142

Remember to be constructive or just give a thumbs up to comments you like.


There were hundreds of comments against this, both constructive and otherwise, alas the committee knows better and will do whatever they want.


I think the water is somewhat muddied by the fact that the committee actually _does_ know better than the vast majority of people in opposition, as evidenced by the many uninformed comments in this thread suggesting alternatives that are objectively untenable.

This is not to say that there aren't other viable solutions which would avoid the use of the current proposed syntax, but how do you weigh the advantages of avoiding a subjectively "ugly" syntax against the many other, much more concrete concerns that the TC39 has to evaluate when choosing a proposal? Should "the reflexive reaction of many devs when they first see the feature (without taking any time to try it out) is that the syntax is ugly" just be an automatic veto? If not, how strongly should that concern be weighted? Should an otherwise inferior proposal be accepted instead merely because the syntax is slightly prettier?

Ultimately, I think you need to have a person or group of people in authority who will look at all available options and make an informed decision, even over the objections of the uninformed majority. Right now, the TC39 _is_ that informed authority.


The solution that TC39 voted is based on requirements that can only be satisfied by having the ugly `#`.

Namely they voted for encapsulation / hard-private [#33] as well as comparing private properties of two classes [2], which as a result makes the only possible syntax the one with the `#`.

Unfortunately this comes at the price that once browsers implement this it will become history ( same as the `with` statements [3] and `labels` with `continue` [4] ). Because of backwards compatibility these will never be removed.

Maybe in 2022 TC39 will decide that "use static-type;" will be a mode, such as strict mode, where you can write statically typed JS ( great idea, btw ), where this proposal will make no sense. Another "use class-inheritance;" mode would also finally end the abuse of prototype inheritance with syntax sugar. In this future the `#` will be just a huge annoyance.

#33 : https://github.com/tc39/proposal-private-fields/issues/33

2 : https://github.com/tc39/proposal-class-fields/blob/master/PR...

3 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...

4 : https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


I can sort-of understand the desire for the values to be hard-private, but I think even that would be achievable without new syntax[1]. However, they also want the existence and names of the properties to be hard-private, which seems excessive. (And linguistically inconsistent with the choice of non-hard-privacy for symbols.)

[1]: https://github.com/tc39/proposal-class-fields/issues/177#iss...


May be by actively making Javascript Shorter and uglier, to steer people away from it, and making JS a compiling target only?

I mean whenever I see # I thought I am either on tweeter or the code was commented out.


It feels like in this instance the reflexive reaction of the developers is what made the passing of the proposal more likely by putting the committee in a psychological position where they're dismissing large amounts of feedback, making them more likely to throw out the proverbial baby. Had there been no discussion about the syntax, maybe the comments saying "we don't need this feature" would have been listened to.

It also didn't help that library authors are over-represented in the committee relative to the regular users of the language.

Ultimately, I agree that we need to have an authority to make the final decision and it helps if it's informed, but we need to be aware that it's not going to be perfect and it will have blind spots, so perhaps a way for people to veto those decisions should exist.


> It feels like in this instance the reflexive reaction of the developers is what made the passing of the proposal more likely by putting the committee in a psychological position where they're dismissing large amounts of feedback, making them more likely to throw out the proverbial baby.

Thank you for putting that into words. That's what I was initially trying to express when I talked about "mudding the water", but the second paragraph sorta took my train of thought in a different direction.

I can't help but think that if there weren't so much discussion about the syntax, and consequently so many people willing to throw their support behind any alternative proposals merely because they avoid that particular syntax, some of the more substantial concerns about this proposal might have gotten a bit more consideration due to the higher signal-to-noise ratio.


For those of us who don't follow closely, how diverse is the membership of TC39? Are Mozilla, Safari, Edge, or other facets of the community well-represented, or is it just a front for the Chrome team?


Different subcommittees have different representation, but it’s generally diverse at least amongst the browser vendors. Often non-vendor web companies like Facebook take part in discussion too, and the current spec editor is Kevin Smith, who works at Microsoft. I believe a major proponent of this specific proposal was Daniel Ehrenburg, who used to work for V8 but now works at a different company that contracts for all of the JS engines.


Any company on this list[1] can send a delegate to a TC39 meeting, and at most meetings there are generally around 45ish people, from lots and lots of different companies and perspectives.

A particularly important member to point out is the JS Foundation, which sends devs of babel, lodash, etc to TC39 meetings as well.

1: http://www.ecma-international.org/memento/members.htm


TC39 has representatives of all major browser makers and various other companies doing web stuff.


There is even an issue [1] that counts the votes for stopping this proposal.

IMHO "No solution" would be better than "bad solution" in this case.

1 : https://github.com/tc39/proposal-class-fields/issues/100


If you don't want the solution to exist, why do you care what it ends up being? You won't use it. You have no horse in the race.


Reading / maintaining / working with other people's code?


@gaardani that clearly will work, as evidenced here https://github.com/tc39/proposal-class-fields/issues/100#iss...


The rationale for the "#" syntax is that it makes it clear that the field is NOT an object property. This is an important distinction because you can do this:

  class Example {
      #myVar = 100;

      getPrivateMyVar() {
          return this.#myVar;
      }

      getLocalMyVar() {
          return this.myVar();
      }
  }

  const example = new Example();

  example.myVar = 200;

  console.log(example.getPrivateMyVar()) // 100;
  console.log(example.getLocalMyVar()) // 200;
I agree the syntax is terrible. But you need to be able to distinguish between the own object property myVar and the private field myVar.


Access modifiers, as the name suggest, are an accessibility feature not a scope feature (like let).

example.myVar = 500 should throw an access error.

You don't need to distinguish because you shouldn't be shadowing private variables.


If `example.myVar = 500` can throw errors, then is the private field really private? Since now it's existence can break the public interface, and changing it to `myOtherVar` during a refactor can break existing code.

That removes a major benefit of private fields (which is to be able to change implementation details without breaking the public interface)

I don't think anyone really loves the syntax, but there doesn't seem to be much of a better way of doing it.


What happens if you do `example.#myVar = 500`? Does it throw an error? Wouldn't it be the same situation?


as of right now, `example.#myVar` isn't valid syntax, which is the reason that the # sigil was chosen.

It's not possible to have current code that works like that, so defining new properties for that code (that it can only be used inside the class as a private field) isn't breaking anything.

In other words, outside of the class implementation, `example.#myVar` is always an error, regardless of the existence of a private field or not, and it will always be an error with or without this proposal. And inside the class it's only legal if the private field was defined in the class.


The difference is that when you type example.myVar = 400 you are setting a property names "myVar" on the object to 400. When you type example.#myVar you are trying to set example's private field to 400. The intentions are distinct and it is not costly to determine at the call site what you're trying to do.


What if I have private values I want to access programmatically? Ie. fields = ['#foo', '#baz', '#bar']; fields.forEach(field => { this[field] = frobnicate(field) }); ?


I don't know what the spec's solution for that would be, but what you've typed would not work. Specifically because when I say `this.#foo` it is not a property on the object named "#foo". It is just the syntax for looking up a private field referenced by the literal #foo.


The spec's solution is to not solve that problem ;)

Dynamic property access isn't allowed for private fields, so it kind of side steps that whole issue.


Correction: What happens if you do `example['#myVar'] = 500`? Does it throw an error? Wouldn't it be the same situation?


dynamic access to private fields is considered a "non-goal" of sorts, so `example['#myVar']` will act the same as it does now, it will always refer to the public property of that name.

https://github.com/tc39/proposal-class-fields/blob/master/PR...


Then what about inside the class? What about `this['#myVar']`? Is it different from `this.#myVar`? If they are different it's very inconsistent and IMHO a lot worse. If they are the same, it's more confusing and still worse than the alternative suggested... what a mess.

On one hand I follow a more functional programming style so this won't affect me but on the other I worry about trying to understand other people's code (especially very serious programming [tm]).


`this['#myVar']` will access the public field named `#myVar`, so it's the same as the `example` method.

>If they are different it's very inconsistent and IMHO a lot worse.

It is called out in the link I posted above as a "downside", and I agree that it sucks, but there aren't any other good options for this without breaking compatibility with current code.

>I worry about trying to understand other people's code

Luckily there is one big benefit to this that makes the impact of the weirdness surrounding the naming much less awful. Because of the "hard encapsulation" that the private fields have, they are literally and explicitly un-viewable, un-accessible, and un-usable outside of the class body.

So the amount of complex meta-programming and many of the reasons you'd want dynamic property access in the first place (iterating, monkey-patching, using arbitrary strings as keys, computed keys, etc...) aren't applicable, and if you really want those features but also with privacy, you can nest a plain object as a private field and work with it that way just the same.

So it may have some gotchas, but because the proposal is intentionally restricted as much as possible, and it explicitly disallows a lot of the metaprogramming that can be common and it only allows a very simple lookup syntax, the weirdness is very well contained, and at worst will be confined to between the opening and closing brace of a `class` statement.


That's the thing, current code is not using the `private` keyword since it's not valid, so it would not break anything and would be totally retro-compatible. `example.myVar` will still work whether or not it's possible to create a private prop called `myVar`, because it's just not created now since you cannot do `private myVar` now. Now, I do agree that it might be confusing in the future as well and might be not future-compatible, but it is for sure retro-compatible...


But then what happens if you have `private myVar` and you need to access the public `myVar` from within the class?

That's not an extreme hypothetical, it was a real example from someone trying to use this feature. They had tried to emulate private fields with an underscore before, people started using the private variables, and now they want to refactor while keeping the current "private-turned-public" variable working the same.

I'm sure you can come up with answers for most of those things, but will they really be easier to understand than the current proposal? I'd hate if I have to look around in the class any time `this.anything` happens to see if it's private, public, shadowed, a getter/setter, etc...

`this.#myVar` is explicit, it's obvious, and even if it's ugly as a sin, you know it's not doing something "normal" right away.


If `myVar` is defined as private then it cannot be re-defined as public... It seems simple. It's the same as normal variables: what happens if you define myVar as `const` and then you want to redefine it as `var`? Well, you cannot, you'd have to work around it instead.


But then the private variables can impact code outside of the class, and and they are no longer truly private.

Imagine you are using a library and extending it adding a few properties for usage in your app, and one patch upgrade your app breaks because the `example.tag` stops working because the library decided to add `this.tag` as a private variable.

Imagine React decides to use this, and they add a private `this.internalState`, but all react components are extended from that. So now all react components can't use `this.internalState` and if the react team ever changes the name of the private variables, then it is a breaking change and can cause code to stop working.

You can say "well don't do that" all you want, but a good portion of the web uses techniques like that, and breaking code because you feel they are doing it wrong doesn't make a healthy ecosystem.


Ah I see, that makes a lot of sense, thanks for the clarification. I still think it'd have been a fair compromise anyway, but it's not ideal and not easy as I thought.


> then is the private field really private

What are some of the other languages that interpret "private" as never exposing the existence of that field to a public consumer? Most languages I've used don't expose the _value_ of the field...


I'm honestly not sure, but even taken in isolation it's a convincing argument to me.

See [0] for some info straight from the proposal, but the gist is doing it this way makes it so that you never have to worry about name collisions for private fields. Subclassing, superclassing, and object "monkey patching" all can continue to work as-is with no changes, and none of them have to worry about the existence of private fields complicating implementations, and the classes with private fields can feel free to change and rename them as much as possible, even within patch versions of libraries, since they cannot impact any code outside of the class under any circumstances. That's a pretty powerful guarantee to give which GREATLY simplifies working with them.

If I want to extend the react component class, I don't need to worry that my `#component` private field is going to break if an update to the react component class adds their own `#component` field, or if a user of my library tries to do something like this:

    const fancyObj = new FancyObj()
    fancyObj.tag = Symbol('tag')
Which I'll admit to having used in some cases where I want to tag a bunch of otherwise identical objects which will be thrown into an array and then be able to easily pluck out the ones I tagged later. Without true encapsulation, that code above would break if they changed the private interface to use the `.tag` field internally, and I would have no idea because it is consitered a private interface and wouldn't need to be documented or maintained across versions.

[0] https://github.com/tc39/proposal-class-fields/blob/master/PR...


Huh, they just took all the issues with inheritance and made them more confusing!

There is nothing addressed here that can't be solved with composition. This seems like an odd step for an aspiring functional language to take...


But JS isn't aspiring to be a functional language, it's adding new syntax and changing itself to better solve the problems that it is currently being used to solve.

Some of that is pushing it in a functional direction, some in a "classic OOP" direction.

Much like classes in the first place, this is a feature added to the language to stop the proliferation of stop-gap solutions and standardize on one implementation for most.

Sure, I won't be using this feature, just like I won't be using classes at all in most cases (React components being one exception), but many will, and if this isn't added, they will continue trying to solve problems with solutions which are more complicated, slower, and buggier than this. All the talk about how it's not the "right" solution doesn't matter.

To use an over-the-top metaphor: People are jumping out of planes, and you aren't going to stop them, so the very least you can do is give them a well tested parachute and a map of where to safely land.


This is how most object-oriented languages work, people just don't realize it. Here's some Java code:

    class Base {
        private int field;
        
        Base() {
            this.field = 1;
        }
        
        void baseMethod() {
            System.out.println("Base.field = " + field);
        }
    }
    
    class Derived extends Base {
        private int field;
        
        Derived() {
            this.field = 2;
        }
        
        void derivedMethod() {
            System.out.println("Derived.field = " + field);
        }
    }
    
    public static void main(String[ ] args) {
        Derived d = new Derived();
        d.baseMethod();
        d.derivedMethod();
    }
It prints:

    Base.field = 1
    Derived.field = 2


This is not how Ruby and Python works, I believe. I guess it's debatable which paradigm JavaScript is more similar to.


Python name-mangles properties that start with "__" to emulate privacy. Run:

    class Base:
      def __init__(self):
        self.__field = 1

      def baseMethod(self):
        print("baseMethod " + str(self.__field))

    class Derived(Base):
      def __init__(self):
        super().__init__()
        self.__field = 2

      def derivedMethod(self):
        print("barMethod " + str(self.__field))

    d = Derived()
    d.baseMethod()
    d.derivedMethod()
And it prints:

    baseMethod 1
    barMethod 2
Ruby doesn't really have fields that are private to subclasses, but Ruby also embraces monkey-patching, so that's not entirely surprising.


Not as far as the spec is concerned. They decided that private variables should be completely scoped to the class.

"Having a private field named x must not prevent there from being a public field named x, so accessing a private field can't just be a normal lookup. This is only an issue in JavaScript because of its lack of static types. Statically typed languages use type declarations to distinguish the external-public/internal-private cases without the need of a sigil. But a dynamically typed language doesn't have enough static information to differentiate those cases." [0]

There are also performance concerns to changing the lookup logic without the sigil. More info in the link.

0: https://github.com/tc39/proposal-class-fields/blob/master/PR...


I still don't see why this is an issue in Javascript. PHP, the canonical hate-it dynamically-typed language, does not have this issue.

Sure, you say, that's because in PHP a public property and a private property cannot have the same name. Correct. Why is this a requirement? What problem is this trying to solve? In e.g. older Python we would use the convention of a leading underscore to indicate that a property is private, even if technically one _could_ access it publicly it was understood that is a bad idea to do in practice. It's not a security issue - in every language one could read the "private" properties by some method or another. Reflection, for instance. Or, back to PHP, by casting the object to an array (I did mention that PHP is the canonical hate-it dynamically-typed language).


I really recommend you read over the FAQ that is in the proposal at [0], it answers most of your questions.

The problem is that it seems a "private by convention" system isn't private enough for many library authors, who are finding their private internal methods being used regardless, and then after some time becoming ossified leaving the maintainers in a tough situation. Support the "private" interface even though they shouldn't have to to avoid breaking a significant number of users, or break the "private" interface and leave many developers with code churn.

Regardless of where fault lies (often times it's one library using the private interface of another library, and the developer gets caught in the middle), this is a bad thing, so people began workarounds like complicated closure systems or weird-looking interfaces which emulated true private fields without having support for them.

This started becoming popular enough that it was decided that adding them to the official syntax would be better, and unlike in PHP or other languages, there is no way around it here. Serializing or casting the object doesn't expose private fields, and there is no reflection methods or anything that would allow it. They are truly private.

I personally share your feelings that this isn't an issue that needs solving (i'm of the opinion that the lack of easy truly private properties had a non-zero impact on the rise of javascript, and the ability to tweak private interfaces in your code is a net benefit, even if it gives developers rope to hang themselves with), but the pain felt from it is real for many, and the workarounds they were using were not only slow and difficult to use and maintain, but also very hard to understand, and this alternative is a much better solution in my opinion.

So while I most likely won't be using them, I reluctantly support them being added to the language.

[0] https://github.com/tc39/proposal-class-fields/blob/master/PR...


From the syntax proposal:

> Having a private field named x must not prevent there from being a public field named x, so accessing a private field can't just be a normal lookup.

Why do classes support public/private fields of the same name in the first place? This seems fraught by nature?


It's more of a side effect that the class can define these properties of the same name. The real goal is that in the following example, the private property #x is not affected.

  class A {
    #x = 100;
  }

  const a = new A();
  a.x = 200;
On top of this, you should be able to define private variables and methods in derived classes without interfering with the base class private properties:

  class A {
    #x = 100;

    getA() { return this.#x }
  }

  class B extends A {
    #x = 200;

    getB() { return this.#x }
  }

  const b = new B();
  b.getA() // 100
  b.getB() // 200;


This example seems like something you shouldn't be able to do. Now you have 2 private '#x' properties with unique values. It's very surprising.

Intuitively, you would expect the subclass to essentially be saying "my version of this variable is equal to 200, not 100". Then both calls should return the same result (200)


The spec (and the committee) has defined "private fields" to mean that anything outside of the defining class (including subclasses) should have no knowledge of them. If your subclass needs to know about the property, make it "soft private" by prefixing it with _.


Another comment in this thread noted this is how Java works. I very much agree with you, but I guess there are different interpretations of how this should behave.


I’m guessing the answer is to do with the fact we’re dealing with a prototype chain rather than “regular” classes, and the historical fact that everything is basically public anyway


But you could do the same with "_".

I think the feature is good but couldn't they find a different character than one used for comments almost everywhere else?


Well a lot of characters are already taken. Starting with _ is already valid JS syntax so it would break existing code. @ was a popular symbol for this but got taken by decorators.


Also, the # is traditionally the "protected" modifier in UML.


UML should not factor into this discussion


Any established prior convention can factor into such a discussion, even if it doesn't concern javascript (and since it didn't have private properties before, all established prior conventions will be from other languages and/or domains).


There are many obscure systems out there (yes, UML is obscure). If you try to consider conflicts with all of them you cannot do anything.


What ever happened to using double underscore for private fields


> is NOT an object property

But it is an object property, just like everything else attached to "this".

That "this.foo" is not "this.#foo" that's because "foo" is a different key than "#foo".


Not accurate. The private fields described in the spec are not properties on the object's map. Thats why they need to differentiate intention at the call site.

The current idea is that private fields are kinda like this:

  export class Bar {
      #foo = 100;
  
      setFoo(value) {
          this.#foo = value;
      }
  
      getFoo() {
          return this.#foo;
      }
  
      getFooFromOtherBar(otherBar) {
          return otherBar.#foo;
      }
  }
  
  // similar to (but implemented differently I'm sure)
  
  const barPrivate = new WeakMap(); // properties are only private if this is never exported
  
  export class BarWithoutPrivateFields {
      constructor() {
          barPrivate.set(this, {});
          barPrivate.get(this).foo = 100;
      }
  
      setFoo(value) {
          barPrivate.get(this).foo = value;
      }
  
      getFoo() {
          return barPrivate.get(this).foo;
      }
  
  
      getFooFromOtherBar(otherBar) {
          return barPrivate.get(otherBar).foo;
      }
  }
It is NOT a property key!


It's not merely a different key; it's a completely different _type_ of key. I'm not sure how it's implemented internally, but `this.#foo != this['#foo']`.


Objects in JavaScript are just maps, so technically speaking if they disallow "this[#foo]", it's just a cheap trick.


They don't disallow `this["#foo"]`. It's a completely different thing than `this.#foo` though. Think of it like this:

    this["#foo"] = "Value A"
    this.#foo = "Value B"
    
    console.log(this["#foo"]) //=> "Value A"
    console.log(this.#foo) //=> "Value B"
That's why people are saying that `this.#foo` is not an object property. You can think of it like one if you want, but it's not really the same thing.


I only write a tiny bit of JS (and I mostly hate it to be honest) but what's the reason for this difference? Why not make them object properties to make the language more regular?

I know this is very non-constructive but reading through these threads and these proposed improvements to modern JS the expression "polishing a turd" pops up in my mind repeatedly. That people chose to bring this thing out of the browser to use as a general purpose language is rather baffling to me. I can't wait for WebAssembly to become more mainstream, then I'll be able to archive my little knowledge of JS deep into my brain, alongside Perl and TCL.

</nonconstructive rant>


If they were object properties, then they wouldn't really be private.

You can't throw an error on `this["#foo"]` because then you'd be publicly exposing the fact that a private field `this.#foo` exists.


Above _ryan_ posts that the main reason they implemented it like this was so people wouldn’t use them and cause library maintainers pain.

But just “knowing they exist” is not causing any pain for a library developer, as long as they can’t read the value. So I don’t understand the need to also hide the fact they exist. What’s the use case there?

It seems you get all the benefit with almost no downside by just making them non-read/write but by going fully to non-enumerable you not introduce two massive downsides:

1. Introducing a whole new syntax that has multiple irregularities (property access) and uses a special character.

2. Now can confusingly have the same public and private names on the same class.


  1. Introducing a whole new syntax that has multiple irregularities (property access) and uses a special character.
I sincerely fail to see how this has irregularities. It's straightforward. x.#prop is always a private field access and x.prop is always x["prop"] which is always an object property access.

  2. Now can confusingly have the same public and private names on the same class.
I know what you're saying, but the reason it is confusing is because it is incorrect. You cannot have have any same public and private names because private names must start with # and public names cannot start with #. Private field names exist only in a class-definition-bound namespace.

I know you can't think of a use case. But the committee of TC39 (language maintainers, popular library creators and maintainers) have thought of the use cases and have clearly decided it is useful.


I agree with you and I had this same question when the article discussing private class fields was posted here a few days ago.

There has been a lot of discussion regarding public and private keywords here: https://github.com/tc39/proposal-class-fields/blob/master/PR...


The difference with TypeScript is that TypeScript is able to statically disallow usage of such private values, at compile time.

JavaScript is not static, you don't have a compiler that can protect against access, so you need info that is preserved at runtime.

`#count` in this case is a different name than `count` and via this naming convention it's able to protect access. I don't get the point though, since people already use underscores as a soft mechanism for protecting access to private stuff and in a dynamic language like JS I don't think you need more.

I also think the TC39 proposals are doing more harm then good and they should just stop changing JavaScript. Just leave it the way it is, thanks.

"Promise" for example sucks, in spite of receiving early feedback, because TC39 is run by certain individuals that outright reject feedback that doesn't comply to their world view.


Why can't the public/private distinction, if denoted with a "private" keyword instead of a # be preserved and enforced at runtime? The difference between `private count` and `#count` is purely syntactical.


Because the difference between `object.count` and `object.#count` is NOT purely syntactical. Information is needed at the call site to determine if it is a private field access compared to an object property access. This is because a private field, as defined in the spec, must not interfere with object properties.


> Information is needed at the call site to determine if it is a private field access compared to an object property access.

Is there? The object.#foo syntax tells you it is private, sure… but you still need know if access is permitted or not. For that, you need to look at some information on object and make a decision, but that information could also inform you as to whether or not the access is to a private field at all. Consider for object.foo, the following:

  1. look up, internally in the interpreter, the class definition (recorded when parsing the class {} block)
  2. Is .foo private? If no, behave "normally"
  3. If yes, decide if access should be allowed.
What about that doesn't work? If that does work, then, the # is pure syntax.

One thing I'm curious about, since you seem adamant that this isn't syntax (particularly since the docs raise the peculiar "SyntaxError" — which implies determining at parse time whether a give obj.#thing is valid): is it only accessible through this.#foo? That is, if I have a class with a member function that takes another instance of the same class, is JavaScript going to tell me that I can't access private fields, despite those being on the current class? (This is fairly different from most languages, and makes some things impossible to express while keeping internals private.)


First, about accessing private fields on members of the same class: the spec will allow this via `other.#foo`.

The reason I said that the difference between `object.foo` and `object.#foo` is not purely syntax is because they are two completely different actions. The first is a lookup in the object's property map/prototype chain. The second is a private field lookup.

`object.foo`:

  1. Check to see if there's a property named "foo" in `object`'s property map.
    1a. If yes, return the value.
    1b. If no, continue.
  2. Does this object have a prototype? 
    2a. If no, return undefined.
    2b. If yes, repeat these steps starting from 1 using this object's prototype.
`object.#foo`:

  1. Test to see if you're in a class.
    1a. If no, throw a Syntax Error.
    1b. If yes, continue.
  2. Test to see if `object` is an instance of this class.
    2a. If no, throw a Syntax Error.
    2b. If yes, continue.
  3. Test to see if the class defines a private field *#foo*.
    3a. If no, throw a Syntax Error ? (Not positive on this one, it might just return undefined).
    3b. If yes, continue.
  4. Look up this class' private fields for `object`.
  5. Get the value for *#foo*. 
  
In case it wasn't clear: the private field `object.#foo` is NOT a property on `object` named `foo` and marked private. It is a field which exists in a namespace only accessible to the class definition. Without the # sigil, there'd be two issues. See [0] for a pseudo example of how private fields really behave.

The first issue comes from a decision made in the spec by the committee: private fields must not interfere with object properties. This essentially means that an object can have the private field #foo AND the object property "foo" (as I described here [1]). Without the #, the fields would have to exist in the same namespace as the object's properties. If you error out when `object.foo` is accessed outside of the class definition, it would not fit the spec's definition of "private". [2] [3]

The second issue is that without the #, the compiler would need to determine at the call site which lookup method to use, and they decided this would incur too much overhead on every single lookup in the already complicated property lookup logic.

0: https://news.ycombinator.com/item?id=18707421 1: https://news.ycombinator.com/item?id=18706363 2: https://github.com/tc39/proposal-class-fields/blob/master/PR... 3: https://github.com/tc39/proposal-class-fields/blob/master/PR...


>This is because a private field, as defined in the spec, must not interfere with object properties.

Why couldn't it? E.g why not let it interfere...


#aargh

Please roll this back, what a nightmare!


> #aargh

Many system programmers will think this line is commented out. Indeed what a nightmare!


Yup.

The muscle memory is so strong, when writing Javascript/Typescript I type # by accident sometimes.

But then, // is one of the most commonly used operators in another language I use, so it's weirdly symmetrical :)


Curious: which language?


Perl, the defined-or operator.

Like ||, but // tests definedness instead of truthiness.

The equivalent in several other languages is ??, which is uglier imho, but it's just syntax. https://en.wikipedia.org/wiki/Null_coalescing_operator

I use // and ?? often as it's conceptually clean, fast and concise. When available, it arises naturally in logic like caches, memoizations and defaults. //= is pretty useful too, and I'm surprised it's not more widely available.


Python uses it for integer division. Typically it is meant as "divide and floor" as far as I've seen.


Wouldn't most system programmers think it's a macro?


If the javascript class hackers want #these #things on top of this (this this this...) I don't begrudge them - it puts the functional style in an even better light, where of course keeping private state is already simple and routine.



Wow, what a shitty syntax choice. Why not just stick with private/public (public by default)?


I can't find it but I remember reading through the rationale. I don't fully recall if I understood or agreed with the reasoning but I recall there was reasoning that was more than just visual preference.


Of course.

That abomination requires as much rationale as they can produce in the given time frame.

Good design doesn't require such degree of mental gymnastics.


You can't really do good design if you have to remain backwards compatible with the entire internet.


Try explaining this to my peers who just don't appreciate why JavaScript is such a mess.

Is this problem found anywhere else in the programming world at this scale?


There are similar concerns with C(++) and Java.


Coming from C# which uses public private keywords there is still a convention of naming privates prefixed with a underscore so when reading the code its immediately obvious its a private.

Looks like Typescript conventions say not to do that. Either way the compiler should throw an error if trying to access a private incorrectly.

In JS I guess it helps reduce runtime errors since there is no compiler to check for you and again very clearly visible in code its a private.

Its sort of old school, like Hungarian notation where you would prefix variable with type identifiers except they really mean something.


A convention followed by Hungarian notation refugees.

I cringe every time I have to deal with such codebases.


Almost as bad as m prefix.


What is wrong with the m prefix for members?


I don't write C# but I also dislike this notation in C++. If I want to make it obvious that I'm accessing a member then I write "this->member".

IMO it was a mistake for C++ to allow the "this" to be implied for members, it makes it a lot harder to figure out what C++ code is doing and what's dealing with member variables and methods vs. globals. At the same time "m_" prefix only solves half of the problem because it doesn't help with method calls. That's why I prefer to drop the 'm_' and just put the "this->" everywhere, even when it's not mandatory.


But what the method resolves to could be very different in the case of an inherited hierarchy, or where a base function is overridden in a child class. It has never been a difficulty even with colossal codebases that the function that it is resolved to might be elsewhere, in a child. If anything, it's one of the great strengths of the language.

The m_ syntax is kind of ugly but adding a this-> every time seems foolish, given that either the member is protected or public if you're modifying it in a base class. In the case of complex inheritance, you might be running into problems with ambiguity of names anyway.

m_variable (or a sensible member naming convention, e.g. a prefix) helps to distinguish between local variables, which is important in complicated classes/functions.

This proposed # for JavaScript looks insane, coming from the well-established, tried, and tested (and perfectly functional and useful) systems found in C++, Java and C#. It's like it's adopting a terrible syntax in order to solve a problem that doesn't exist. Perhaps I am misunderstanding.


Useless prefix better replaced by making use of this. or IDE tooltips.


m is shorter than this and not everyone uses an IDE.


If the point is to write legible, explicit code then the extra 4 characters of "this->" over "m_" shouldn't be a deal breaker. It also has the advantage to save space and reduce noise in locations where you really don't need to make it explicit (like declarations in particular where you obviously don't have the "this" but you'd need to add the m_ prefix).

If the point is to write super dense code for some reason then don't use anything at all.


Still not an argument to plague source code with it.

I for one am more than happy not to write Hungarian notation any longer.

Even Microsoft style manuals now advise against it for modern Windows code.


Yep, that is another one.


I’m also reminded of the less venerable, but still sort of “instant classic” feeling, choice in the design of Golang, where publics are named with a starting uppercase letter, while privates are named with a starting lowercase letter. (Definitely wouldn’t be a choice that would be backward-compatible with existing JS, but neither would prefixed-underscore privates.)


The same trick is often pulled in C++, but mostly for another reason: to prevent name clashes with methods since they're in the same namespace.


People coming to JS from other languages often ask how to create private variables, the answer is to use a local variable and closure. And with ES5 you can also use defineProperty


What's the problem with public/private fields?

Language design is hard but is there legitimate criticism besides subjective "I don't like this" ...


I think that now that Edge is moving to Chromium, they can just push whatever shitty syntax they want and Firefox will be forced to follow suit.

I wouldn't be surprised if this here is them giving that dominance a first shot. I'm sure they realize that developers will think it's horrible, but at the same time it's also not a problem. Nothing will break because of this, no company will be disadvantaged by it (barring Mozilla ofc). Perfect opportunity for testing the waters of a newly obtained monopoly position.


I would be very surprised if a proposal that's at least over a year old (first commit in the GitHub repo was May 14, 2017) was part of some master plan for Google to test their dominance after Microsoft recently decided to kill Chakra. Ignoring timing, it's a pretty terrible way to test their monopoly position since it's obviously not going to help Google's business unless they plan to start manufacturing the "3" key on JavaScript developer keyboards. Why would Mozilla possibly spend the effort push back on this? TC39 comes up with things that are controversial (on GitHub issues at least) all the time.


Looks like a comment hash to me.


What happens when it reaches version 8.0?


Google search results will be rendered useless.

"V8 release v8"

At least when it's spelled out like this, they always use capital V8 for the engine and a lowercase v8 for the version.

I can imagine the verbal V8/v8 confusion probably forces everyone to say "version 8"


They're going to skip a version and go straight to 9.0

maybe


Total protonic reversal.


Unrelated but .dev is a new Google TLD where all the domains have HSTS enabled by default.

https://shop.gandi.net/en/domain/suggest?search=hackernews.d...


.app domains have HSTS enabled by default too. I think all domains should be HSTS enabled by default in the near future.


Personally, i’d like to see them focus less on super-rapid releases, and more on consistency of builds and stopping major breakages across platforms.

It makes it much more difficult to maintain downstream builds when the build-system breaks completely for indeterminate amounts of time.


I wonder how many people will skip using Intl.ListFormat because it insists on Oxford comma in English. I know I’ll be skipping it. CLDR really missed the semantic nuance there—not that it could readily have included it. The problem is that it’s just too blunt an instrument. (Further reading: http://cldr.unicode.org/translation/lists, https://en.wikipedia.org/wiki/Serial_comma .)


It's weird that the oxford comma is included in the en-US locale, but not in the en-GB one.

You can check how the locales work here: https://github.com/unicode-cldr/cldr-misc-full/tree/master/m...

Go to the locale folder and then look at the listPatterns.json file


Out of curiosity, why is the API's insistence on the Oxford comma a downside, seeing as it works for almost all lists? Is it due to overriding editorial preference - e.g. news orgs style guides?


The linked Wikipedia article is long, but goes into some depth on reasons and situations where it may or may not be desired. In American English it seems to be mostly a matter of preference and style guide, but in Australian English there is also semantic meaning to the comma, where it is possible in a carefully crafted sentence to convey quite a different meaning by the addition or removal of a comma; and unless there is semantic or possibly parsing value to be gained by the inclusion of a comma, it is broadly (though not universally) agreed that you shouldn’t.

As noted by narrowtux, not all English locales use the Oxford comma; en-AU also doesn’t, which mollifies me.

The simplest style of example I can think of is nesting conjunctions: “the difference between A and B, and C and D”. (This example isn’t great because it depends on nesting and has only two items in each list; but it’s the first that springs to my mind. There are others that don’t require nesting or only two items, though normally not quite so clear-cut.) Removing the comma or shuffling things around in any way would completely change the meaning of the sentence. This is the sort of subtle thing that some will miss when writing, but in speech it’d be very clear.


I suppose I could look this up, but maybe someone here knows. Is cached JS re-parsed on every page load or is the AST (or some sort of bytecode) stored as a blob on disk for faster loads from cache?


It looks like you can leverage this:

https://v8.dev/blog/improved-code-caching

using this:

https://www.npmjs.com/package/v8-compile-cache

Or see the options with "cache" in their name, here: https://nodejs.org/api/vm.html#vm_new_vm_script_code_options


Thanks! Looks like the first link answers my question.


why focus on facebook when measuring performance?

I thought they have like 10.000 websites they measure


We do indeed measure improvements against more than one website. We wouldn’t want to improve website X while regressing the rest of the internet. See https://v8.dev/blog/real-world-performance (from 2016):

> We now monitor changes against a test suite of approximately 25 > websites in order to guide V8 optimization. In addition to the > aforementioned websites and others from the Alexa Top 100, we selected > sites which were implemented using common frameworks (React, Polymer, > Angular, Ember, and more), sites from a variety of different geographic > locales, and sites or libraries whose development teams have > collaborated with us, such as Wikipedia, Reddit, Twitter, and webpack. > We believe these 25 sites are representative of the web at large and > that performance improvements to these sites will be directly reflected > in similar speedups for sites being written today by JavaScript > developers.


They state specifically in the article that their chart is based on measurements taken from "several popular websites."

Obviously they would want to test Facebook because a lot of people use that website. I'm sure they tested many others as well.


Well.. Facebook runs like a dog, so any improvement is great news.


I consider dogs to be pretty fast :)


Some dogs. Most dogs even. Not my dog. He is a good boy though.


They should start testing against Gmail then :/


Headline is hilarious


Not yet. I can't wait for V8 v8.


Spoiler: V8 release v8.0 · V8


Wow. Very impressive. They are improving at very fast rate. I wonder do we still need to invest in WebAssembly ?


What? How are these even related?


How are they not related ?




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: