New private names proposal [repost]

# David-Sarah Hopwood (15 years ago)

On 2010-12-21 22:12, Brendan Eich wrote:

On Dec 20, 2010, at 11:05 PM, David-Sarah Hopwood wrote:

Please retain all relevant attribution lines.

Brendan Eich wrote:

The new equivalence under private names would be x[#.id] === x.id.

You said "under private names" here, but it should actually be "under the syntax proposed for private names". It applies to that syntax with either the soft fields or private names semantics.

... which is strictly weaker, more complex, and less explanatory.

So is a transposed get from an inherited soft field. Soft fields change the way square brackets work in JS, for Pete's sake!

They do not.

Again you seem to be confusing the "inherited soft fields" proposal with the separate proposal on desugaring the private name syntax to inherited soft fields.

The matter at hand is how the proposed syntax changes affect the semantic equivalences of ECMAScript. I argued against the syntax changes (including those to the square bracket operator) on that basis. Now you seem to be arguing as though I supported the syntax changes. To be clear, I do not support the currently proposed change to how square brackets work in JS, regardless of whether that change is specified on top of the soft fields semantics or the private names semantics. I know that some people consider it to be an improvement in usability, and I disagree that it is sufficient improvement to justify the increase in language complexity. There may be alternative syntaxes that obtain a similar or better usability improvement with a smaller increase in complexity; I hope so.

(One thing is clear to me; driving experts like MarkM away from participating in syntax discussions is not going to help with that. Please reconsider, Mark.)

Talk about more complex and less explanatory. Yes, if you know about weak maps and soft fields, then it follows -- that is a bit too circular, too much assuming the conclusion.

This has absolutely nothing to do with weak maps. We're talking about the consequences of the syntax changes, on top of either proposal.

[...]

So, what if we want to understand '.' in terms of existing constructs? Unfortunately, '#.id' must be primitive; there is nothing else that it can desugar to because 'private id' does not introduce an ordinary variable (unlike 'const id_ = SoftField()', say).

SoftField(), #.id -- something new in either case.

<sarcasm>

Oh, OK, it obviously doesn't matter what we add to the language, it's all the same. Library abstractions, new syntax, major changes in semantics, who cares? Something new is something new. Let's just roll a bunch of dice and pick proposals at random. </sarcasm>

Sheesh. A library class, specified in terms of existing language constructs, is not the same as a new primitive construct, and does not have the same consequences for language complexity.

And what's this "const id_"? A gensym?

A possible convention for naming variables holding private names. It doesn't matter, you're picking on details.

It's tiresome to argue by special pleading that one extension or transformation (including generated symbols) is "more complex, and less explanatory", while another is less so, when the judgment is completely subjective. And the absolutism about how it's always better in every instance to use strong encapsulation is, well, absolutist (i.e., wrong).

I gave clear technical arguments in that post. If you want to disagree with them, disagree with specific arguments, rather than painting me as an absolutist. (I'm not.)

We should debate strong vs. weak encapsulation, for sure, and in the other thread you started (thanks for that). But without absolutes based on preferences or judgment calls about trade-offs and economics.

Tell you what, I'll debate based on the things I think are important, and you debate based on the things you think are important. Agreed?

Rather it introduces an element in an entirely new lexically scoped namespace alongside ordinary variables. This is fundamentally more complex than "id", which is just a stringification of the identifier.

I agree that "private x" adds complexity to the spec.

Good, that's a start.

To be clear, it's not the syntax itself, but the parallel namespace introduced by 'private x' that I find problematic in terms of both specification complexity, and conceptual complexity for programmers.

It adds something to solve a use-case not satisfied by the existing language. There's (again) a trade-off, since with this new syntax, the use-cases for private names become more usably expressible.

It isn't at all clear that there aren't alternative syntaxes that would achieve the usability benefit while not being subject to the criticisms that have been made of the current syntax proposal. Lasse Reichstein posted some possibilities (.# or [#]). The syntax design space has been barely explored in the discussion so far.

The fact that the proposal is entangled with that syntax, so that it is difficult to see its semantic consequences separate from the syntax, cannot possibly be considered a feature of the proposal, at the meta level of the language design process.

Didn't I already agree that it's a good idea to separate "private x" from the semantics, since we have a conflict over semantics?

It's clear how to do that for the soft field semantics, which are defined as a library abstraction.

How do the proponents of private names propose to do that? (This is a technical question, not a rhetorical one.)

So let's do that (my plea to everyone, not just you). Let's separate "private x" syntax, since I now know of a use-case courtesy Mark, and it's a good one (a frozen AST being extended sparsely via soft fields) that wants that "private x" and the sweet dot operator syntax, but on top of soft fields not private property names that require unfrozen objects.

I can't parse that sentence; please clarify.

The inherited soft fields approach is more entangled with its reference implementation, which is not the efficient route VM implementors can swallow.

I think you're being rather patronising to VM implementors (including yourself!) if you think that they're incapable of understanding

I wrote "can swalow" not "can understand". "Swallow" and "understand" have pretty different connotations.

Mapping from soft fields to something more efficient that VM implementors will implement is non-trivial.

Little or nothing in VM implementation is trivial. I don't agree with the implication that the soft fields semantics are more difficult to implement than the private names semantics.

There is a separate discussion to be had about whether the form of executable specification MarkM has used (not to be confused with the semantics) is the best form to use for any final spec. Personally, I like this form of specification: I think it is clear, concise (which aids holding the full specification of a feature in short-term memory), easy to reason about relative to other approaches, useful for prototyping, and useful for testing.

I don't mind at all that the correspondance with the implementation is less direct than it would be in a more operational style; implementors often need to handle less direct mappings than this, and I don't expect a language specification to be a literal description of how a language is implemented in general (excluding naive reference implementations).

Requiring all implementors (the primary audience of ECMA-262) to do this mapping, each on his or her own, is a bad idea. The spec should use formalisms that are not at odds with common implementation. But let's wait to hear from more implementors on this point.

We disagree, but yes, let's hear from more implementors.

In the mean time, how about we quit fencing over matters of taste or trade-offs turned into false absolutes, and try to get ahead on semantics: the issues that remain even after separating syntax are the abstraction leaks.

With inherited soft fields, the ability to "extend" frozen objects with private fields is an abstraction leak (and a feature, I agree).

How is it an abstraction leak? The abstraction is designed to allow this; it's not an accident (I'm fairly sure, without mind-reading MarkM).

With private names, the inability to "extend" frozen objects with private fields is a significant limitation.

With inherited soft fields, the transposed get or set magic that changes how square brackets work in JS is a leak on the inside of the abstraction.

"that changes how square brackets work in JS" is out of place here; we are discussing issues that remain after separating syntax, to the extent possible. In the inherited soft field proposal by itself, the syntax is 'field.get(obj)' and there is no magic. That is the proposal that I favour, absent some better proposal for the syntax.

If you don't like x[#.id] / x.id supplanting x["id"] / x.id, it seems to me you have to count some similar demerits against this change.

If we compare both proposals with the additional syntax, they are equally "magical"; the only difference is whether the magic is built-in or the result of a desugaring.

With private names as proposed in full, the #.id syntax which can reflect a private name as an expression result, including the typeof-type or built-in class of a private name, is a definitely both new complexity that makes an overt observable difference between soft fields and private names. No such operator for soft fields.

The weak encapsulation design points are likewise "leaky" for private names, where no such leaks arise with soft fields: reflection and proxies can learn private names, they "leak" in the real ocap sense that secure subsets will have to plug.

As I said earlier, designers of secure subsets would prefer that this leak not exist in the first place, rather than having to plug it. Regardless of your statements above, this is not an absolutist position; the onus is on proponents of weak encapsulation to say why it is useful to have the leak (by technical argument, not just some vague philosophical position against strong encapsulation).

To make progress, we could try to agree on strong encapsulation only. TC39 works by consensus, meaning general agreement, so we may not achieve consensus on strong encapsulation, but if we could, then I think almost all our semantic quarrels go away,

Yes, probably. That was my aim in starting the 'Strong vs weak encapsulation' thread, anyway.

since nothing other than frozen objects being "extensible" via soft fields, but not via private names, would be observable. Perhaps we could even agree that this was a feature of soft fields and be done.

If we somehow all agreed in committee (meaning, without you :-P) on strong encapsulation, then private names wouldn't reflect as values, period.

Right, that is certainly the simplest way to plug the leak.

I raise this even though it looks like it won't get consensus, to give it a fair and clear try.

If we can't get consensus in favor of only strong encapsulation, we might try for consensus in favor of weak encapsulation, with secure subset languages having a solid and demonstrated way to restore strong encapsulation at relatively low cost. But that would have to be solid and demonstrated.

Yes.

I hope this helps. I'm not looking to debate to the death over all of private names vs. all of soft fields, since I'm pretty sure neither will have total victory. We do not want to end up with nothing, if there is a "something" we all could agree on that would materially help developers.

In this light, I'm still sympathetic to weak encapsulation. Mainstream languages do not lock all escape hatches: java.lang.reflect discloses private members,

With a SecurityManager check. I seem to remember security vulnerabilities in that area in previous versions; I'll try to find a reference.

The Joe-E object-capability subset of Java blocks access to the standard reflection APIs, since the security policy applied to them is not what is needed for an objcap language.

e.g. Languages that try to lock all escape hatches fail or breed extensions, often wildly unsafe. In particular, only closures in JS make leak-proof encapsulations and no one (I hope!) wants to change this (debuggers do not count).

As far as I can see, the motivation for soft fields as an encapsulation mechanism (as opposed to for avoiding name clashes) applies to cases where the intended visibility is something other than each object's fields being private to that object. As MarkM has also said, the latter case is indeed better handled by lexical closure encapsulation.

I also see the ocap purity of soft fields, and I like Mark's AST-decorated-sparsely soft fields use-case. But we already have weak maps in harmony:proposals, so one can write such code now, just at some loss of convenience: without square brackets or (even better) dots for convenient soft-field access expressions.

This makes me think we want usable syntax for soft fields, as for anything like private property names. So to close, again I'd like to urge consensus building by splitting out the syntactic proposals where we can. Or even just mentally separating them for now.

Right. The syntactic and semantic proposals for soft fields are already separated; it is only private names proposal that does not separate syntax and semantics. It would be helpful to fix that, although I'm not sure it is possible to completely separate the syntax and semantics of the parallel namespace for private names.

# David Herman (15 years ago)

On Dec 21, 2010, at 10:41 PM, David-Sarah Hopwood wrote:

Again you seem to be confusing the "inherited soft fields" proposal with the separate proposal on desugaring the private name syntax to inherited soft fields.

I think I may have been misunderstanding what Mark was actually proposing/advocating, then. I'm happy to be disabused of my mis-reading.

But on re-reading, I still can't quite make sense of the "Can we subsume Names?" section. There are two syntactic components to the private names proposal:

(1) the bracket-notation is generalized to recognize private name values to look for private properties

(2) the dot-notation and colon-notation are generalized to use private names when their property name is bound by a |private| declaration

But the "Can we subsume Names?" subsection seems to mix these two cases up. To match up with (1), you'd need to interpret all bracket notation as a potential lookup of a soft field, i.e. something like:

e1[e2] ~~>
    let (t1 = e1, t2 = e2) {
        => t2 instanceof SoftField
         ? t2.get(t1)
         : t1[t2]
    }

(where the rewritten brackets are the "true" brackets, i.e., not re-desugared).