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

Possible solution for lack of [] access #104

Closed
rdking opened this issue Jun 4, 2018 · 4 comments
Closed

Possible solution for lack of [] access #104

rdking opened this issue Jun 4, 2018 · 4 comments

Comments

@rdking
Copy link

rdking commented Jun 4, 2018

A few minutes ago, I had an idea about how to solve some of the sigil woes and "just get used to it" learning curve issues with this proposal, and all without needing to replace or remove the sigil.

Let's make # an operator of it's own!

Since according to the spec that comes with this proposal, all objects have a [[PrivateFieldValues]] slot, and the contents of that slot is essentially a sealed object with privateName:privateValue pairs in it, why not use obj# to mean "access the [[PrivateFieldValues]] of obj". LValues ending with the sigil would still be illegal, and the sigil would still only be accessible inside a class declaration.

What this gets us is the following:

  1. no need for private names - Save for the few rules in the statement above, access semantics to this.field would be identical for this#.field
  2. calculated private field declarations
  3. symbol private field declarations
  4. [] notation access to private fields
  5. less unintuitive syntax
  6. singular semantic meaning for #
  7. potential to use private keyword in class declaration as alternate for # in member variable declarations without conflict for meaning.
var aSymbol = Symbol();
var bet = "bet";
class Test {
   private field = 3;
   private ['alpha' + bet] = 'abcdefg...';
   private [aSymbol] = "It works!";

   test() {
      var alphabet = 'alpha' + bet;
      this#[alphabet] = "soup";
      console.log(`There are ${this#.field} private fields in this class.`);
      console.log(`this#.${alphabet} = ${this#[alphabet]}`);
      console.log(`this#[aSymbol] = ${this#[aSymbol]}`);
   }
}

I think that this might be less disturbing to those of us who didn't/don't want the sigil.

@littledan @bakkot @ljharb
Is this a viable idea?

@rdking rdking changed the title A different kind of sigil-related idea.... Possible solution for lack of [] access Jun 4, 2018
@littledan
Copy link
Member

I don't understand what problem this proposal is trying to solve. What's the problem with getting [] access by having a private field which is an object that you can use [] on? It feels a bit more unintuitive to me to have #. rather than .# -- you lose the way that the # can be thought of as part of the name.

@rdking
Copy link
Author

rdking commented Jun 12, 2018

@littledan Nice to hear from you again.

There's nothing wrong with using a private object to gain [] access. That's not really the goal with my suggestion. That's just a positive side effect. As for #. feeling less intuitive than .# to you, I'd attribute that to your familiarity with .# given the past few years of this proposal and the fact that you seem to be willing to accept # as a valid variable character, but only in this 1 circumstance. Losing that # as part of the name is one of the 2 main purposes of my suggestion. As it presently stands, # is not a valid character in a variable name for ES. The class fields proposal doesn't change that either. However, the class fields proposal does make # a part of the name if the field is private. That single syntactic break is the reason why the possible access forms for private fields is necessarily so limited under the current proposal.

Another reason for wanting to get # out of variable names is that having it there is tantamount to "convention over configuration", something else that doesn't fit in ES. Basically, # is not a valid name character, but if you're in a class and declare an instance member name using # as the first character, it's allowed and is taken to mean that the member is private. Last time we had this kind of discussion, you spoke of the mental load on someone trying to understand what's going on. Consider the following:

var #somevar; //1

class Example { 
   #somevar //2
   constructor() {
      this.#somevar = 0; //3
   }
}

Code at 1 is a syntax error under the given proposal. That makes sense to everyone because that's how it's always been. Code at 2 is legal, and uninitiated developers will think of # as a keyword for creating private variables. However, code at 3 requires some explaining because it can't possibly be an operator given the way ES works. Then someone explains to them that the # is part of the name. That leads them to wonder why code at 1 is a syntax error. The current use of the sigil really does introduce a bad break in the language in more ways than one. Here's my version.

var #somevar; //1

class Example { 
   #somevar //2
   constructor() {
      this#.somevar = 0; //3
   }
}

Code at 1 is still a syntax error. Not only is it a double declaration, but also a declaration of a private member outside of the declaration of the containing object. So no problems there. Code at 2 is roughly equivalent to

Example#.somevar = undefined;

which puts somevar=undefined in the [[PrivateFieldValues]] of Example to be cloned when someone calls new Example(). Maybe something different. This is just a possibility. Code at 3 shouldn't require any additional explanation because we've already described the functionality of the sigil. Instead of a mental model that requires you to remember a bunch of quirks that don't fit the existing language, you get just a single operator. Treating the sigil as an operator, solves the mental model issues as well as restores the programming paradigm that all ES users have become accustom to. We shouldn't be so quick to break the fact that ES is a C-like language. It's this fact that makes ES so very quick to learn.

In C-like languages, the tool for accessing a language-specific resource without exposing that resource is an operator. With this proposal (given the spec) you're trying to access an internal, sealed object. That object should not ever be exposed or otherwise directly or indirectly referenced in code as this could lead to a violation of hard private. One of the best ways to accomplish that is to make the sigil a binary operator with the meaning I've given, and with the right-hand term being an access operation. In this way ES code is never allowed access to the internal object.

I get that this breaks with the original idea of replacing the _ people have been using to hint at privacy with a # that enforces it. However, _ was always a valid name character, just not commonly used as the first character until that convention was adopted. What I'm suggesting is that when changing the language, the disruption to the developer's programming style should be as small as possible. This suggestion gives you that without disregarding any of the intentions of the proposal.

As a side benefit, this suggestion opens the possibility for something like this:

var a = {
   #foo: 0,
   next() {
      return ++this#.foo
   }
};

since there's no need for class-specific private names in the implementation. This means that private fields wouldn't destroy the symmetry between classes and constructor functions since private fields could still be easily put on plain objects.

@littledan
Copy link
Member

I don't plan to make this change.

@rdking
Copy link
Author

rdking commented Jun 21, 2018

May I know what it is you didn't find agreeable about this suggestion?

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

2 participants