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

Alternate strawman idea #94

Closed
dead-claudia opened this issue Apr 16, 2018 · 8 comments
Closed

Alternate strawman idea #94

dead-claudia opened this issue Apr 16, 2018 · 8 comments

Comments

@dead-claudia
Copy link

dead-claudia commented Apr 16, 2018

Edit: Inner classes and shadowed properties already exist in this proposal. Updated to reflect this.

Repo/explainer: https://github.com/isiahmeadows/private-data-proposal

The basic concept for my idea is to use scopes (for a very loose meaning of the term) rather than classes. It's mostly compatible with this proposal on the surface, but it avoids most of the gotchas and doesn't require explicit support for protected/friend/etc. The extensibility was pretty easy to spec, and the only complicating factor was making private fields work with subclasses.

Here's some of the benefits it offers:

  • It works with object literals as well as classes. You can do C-style "structs" without having to expose too much of that.
  • It gives you friend access for free just by moving a declaration up a scope and/or exporting a function that reads/writes it.
  • You can actually export private names trivially through exporting accessor/mutator functions, so they're accessible to e.g. subclasses, friend classes, or just other functions that happen to need access to a field or two.
  • You can use this with dynamic imports and namespace imports, just by using the namespace itself. I had to add a separate statement for this, but it was relatively easy to spec.
  • The proposal turned out far simpler and easier to explain/spec than I expected. It's slightly larger than this in scope (mainly due to extra syntax rules, but the runtime roughly equal mod scope checks), but it covers most of the immediate extensibility complaints I've found so far, and it's much more consistent with fewer edge cases. (It took me maybe a few hours in its entirety to get 90% of the details locked down, and another 2 for a little bit of polish.)
    • It helps having a mental model that can be explained with two short paragraphs and a code block. If you read nothing else, that serves as a great summary of what it's supposed to be like. There are few places with curly braces where my private can't be used:
      1. Object destructuring assignment patterns
      2. Named import sections
      3. Named export sections

And yes, it's fully feature-compatible (and mostly syntactically compatible) with this proposal:

  • Class-local fields exist. You just need to declare them in the class.
  • If you just do #x = 1/#x: 1, #x() {}, etc., it's implicitly declared if you didn't already declare it outside of the class/object. (This is where 99% of the syntax compatibility comes from.)
  • Inner classes and scopes can inherit access to private fields defined in outer classes.
  • You don't need an arrow function to access a private field. Being within the declaration's scope is enough.

Notably absent is this: the ability to guard outside access to certain fields to specific classes/scopes/modules. The proper way to handle this is just consenting-adults style: if they say it's private, just consider it private. Unless it's a password or something similarly sensitive (which should be clearly not exported at all), there's no need to truly care too much about it. If it's "protected" or "friend", the subclass or friend class could just choose to expose what you let it see anyways.


If the sigil doesn't suit you, or if the form of declaration itself (the private #foo, #bar) seems odd, I'm not too terribly attached to it. The syntax can change - I'm just presenting concepts here to maybe provide ideas.

Oh, and pardon the ASI - if it looks like it needs a semicolon, you can probably infer it has one inserted there.

@ljharb
Copy link
Member

ljharb commented Apr 16, 2018

Notably absent is this: the ability to guard outside access to certain fields to specific classes/scopes/modules. The proper way to handle this is just consenting-adults style: if they say it's private, just consider it private.

To me this is a nonstarter; one of the primary goals is that private means that it can’t be accessed or observed. Otherwise, you can already use symbols for this.

Separately, this is a departure from the “scopes” model - you can’t get access to a closed-over variable either, it’s truly private.

@dead-claudia
Copy link
Author

@ljharb I had in a previous version the ability to export fields directly and scope such exports, but I ripped it out as a giant kludge. I would separately consider the more broadly useful concept of scoping exports to specific consumers, though, something like export { ... } to "./foo".

Separately, this is a departure from the “scopes” model - you can’t get access to a closed-over variable either, it’s truly private.

Conceptually, it's no different than a private instance field with a corresponding getter + setter. So I'd disagree.

@ljharb
Copy link
Member

ljharb commented Apr 16, 2018

Yes but without the explicit getter/setter, the field - and it’s entire existence - is hidden. That’s the important point.

@dead-claudia
Copy link
Author

@ljharb And that's how my proposal works. I just presented that as another means of explicitly breaking privacy where necessary (one that's a tad less error-prone and verbose enough to be discouraging).

@bakkot
Copy link
Contributor

bakkot commented Apr 16, 2018

  • Inner classes and scopes can inherit access to private fields defined in outer classes.
  • You don't need an arrow function to access a private field. Being within the declaration's scope is enough.

That's how it works in the current proposal too, by the way.

@bakkot
Copy link
Contributor

bakkot commented Apr 16, 2018

See also tc39/proposal-private-fields#93.

@dead-claudia
Copy link
Author

@bakkot Thanks! Updated! 👍

@littledan
Copy link
Member

Thanks for the reference!

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

4 participants