Why not private symbols?

# Domenic Denicola (12 years ago)

Reading through the meeting notes:

YK: You don't need unique symbols when you can just expose private symbols.

BE: Why can't we just have (private) Symbols

BE: Can we unwind the split between private and unique?

These struck a chord with me. Thus, in the spirit of

BE: We aren't going to resolve this now, need to take it to es-discuss

I thought I'd start off the thread.

I believe the proposal is to not have "public" symbols, i.e. you cannot find any symbols via getOwnPropertyKeys or other such operations when given an object. However, if someone hands you the symbol object itself, you can of course use that to access the property's value. This would be sufficient for all the ES spec built-ins and would also provide truly private state for those that don't export their symbols.

The interaction with proxies is complicated, but if I recall had been mostly solved.

Would love to get some discussion on this, as to me it seems like a much stronger alterative than abandoning symbols altogether in favor of GUIDs.

# Brendan Eich (12 years ago)

That's about right, although the details need to be agreed upon.

Symbols would be not reflected easily (not via getOwnPropertyKeys), and would relationship-proxy as sketched in strawman:relationships.

But note how that strawman accentuates the differences between unique and private symbols. But let's say we only have "private" symbols and their exposure is up to the reference holder: they can be exported from modules to become "public", published via the heap as named values, etc.

This seems to neatly separate concerns, but Arv pointed out that for some proxy cases it won't work. I forget what he said exactly, though. Cc'ing him.

# Nathan Wall (12 years ago)

Reading through [the meeting notes][1]:

YK: You don't need unique symbols when you can just expose private symbols.

+1. I've been wondering this for a long time but thought that there was too much consensus around unique symbols to question it.  I'm glad these questions are being asked.  I think symbols should only be private.

# Erik Arvidsson (12 years ago)

On Mon, Jul 29, 2013 at 1:21 PM, Brendan Eich <brendan at mozilla.com> wrote:

This seems to neatly separate concerns, but Arv pointed out that for some proxy cases it won't work. I forget what he said exactly, though. Cc'ing him.

We went through the exercise of only having private symbols but it lead to some issues. Here is one that we identified.

Lets assume we use a private symbol for the @@iterator. The symbol can still be checked because anyone that has access to the right module can get it. It is also important that a proxy for an object, O, is not invoked when you do O[privateSymbol]. This means that it is not possible to create an iterable proxy object, since no trap on the proxy is invoked.

Marks' relationship proposal tries to solve the issue of private symbols and proxies, by inverting the relationship, so that x[r] invokes a method on r, therefore allowing you to create a proxy for r. However, for the built-in meta protocol symbols, you cannot replace them with a proxy to the symbol, since the symbol is already hard coded to use the @@iterator symbol.

Therefore, we need something like public symbols for the meta operations.

# Mark Miller (12 years ago)

Yes. See esdiscuss/2013-July/032339 for more along these lines.

# Brendan Eich (12 years ago)

Yes, thanks. This is a fine pickle!

We need two things. I'd rather have unique symbols and private fields (whatever they are under the hood is unobservable). One can still confine a uniique symbol to keep it "private", if it is used to index objects one creates (and not proxies from outside).

Are we there yet?

# Allen Wirfs-Brock (12 years ago)

On Jul 30, 2013, at 7:02 PM, Brendan Eich wrote:

Yes, thanks. This is a fine pickle!

We need two things. I'd rather have unique symbols and private fields (whatever they are under the hood is unobservable). One can still confine a uniique symbol to keep it "private", if it is used to index objects one creates (and not proxies from outside).

Are we there yet?

Yes, that sounds exactly right and is pretty much were I thought we were in May, with many details remaining to work out WRT private fields.

# Mark S. Miller (12 years ago)

Aside from this confinement issue, all other the advantages that unique symbols have over unique-ish strings seem minor to me. The biggest is default non-enumerability, when we're getting away (admittedly slowly) from enumerability being significant anyway. IMO, if the only advantages of unique symbols over unique-ish strings are these minor ones, then they don't pull their weight.

However, I don't understand the confinement scenario you have in mind. Can you give an example?

# Brendan Eich (12 years ago)

Mark S. Miller wrote:

Aside from this confinement issue, all other the advantages that unique symbols have over unique-ish strings seem minor to me. The biggest is default non-enumerability, when we're getting away (admittedly slowly) from enumerability being significant anyway. IMO, if the only advantages of unique symbols over unique-ish strings are these minor ones, then they don't pull their weight.

However, I don't understand the confinement scenario you have in mind. Can you give an example?

A friend field a la C++ "friend", e.g.:

module ... {
   const friend = Symbol(); // however it's spelled
   class A { ... }
   class B { ... }
}

where fiend is used in the ... elisions but only to access properties of objects known to be instanceof A or B.

# Mark Miller (12 years ago)

On Tue, Jul 30, 2013 at 8:36 PM, Brendan Eich <brendan at mozilla.com> wrote:

where fiend is used in the ... elisions but only to access properties of objects known to be instanceof A or B.

Known how?

# Brendan Eich (12 years ago)

Mark Miller wrote:

Known how?

Lots of ways, e.g., this in bound methods, this after suitable instanceof tests with no mutable [[Prototype]] (e.g., A and B are sealed, manually in ES6 alas, but still doable).

# Mark S. Miller (12 years ago)

On Tue, Jul 30, 2013 at 9:19 PM, Brendan Eich <brendan at mozilla.com> wrote:

Lots of ways, e.g., this in bound methods,

Only useful for instance-private instance variables, in which case you may as well use lexically captured per-instance state.

this after suitable instanceof tests with no mutable [[Prototype]] (e.g., A and B are sealed, manually in ES6 alas, but still doable).

Doesn't resist theft by proxy, since one can easily construct a proxy that passes that instanceof test.

# Brendan Eich (12 years ago)

Mark S. Miller wrote:

Only useful for instance-private instance variables, in which case you may as well use lexically captured per-instance state.

No, "friend" is shared between two classes, no way to make a closure per instance extending over both constructors. Pretend the module above is an IIFE.

Doesn't resist theft by proxy, since one can easily construct a proxy that passes that instanceof test.

Ok, forget instanceof. With this-binding all around, what's the leak? More generally, are you arguing that leaks are hard to avoid, so we need private fields instead? That fits the relationship vs. unique symbol dichotomy.

# Erik Arvidsson (12 years ago)

On Jul 31, 2013 1:39 AM, "Mark S. Miller" <erights at google.com> wrote:

Only useful for instance-private instance variables, in which case you

may as well use lexically captured per-instance state.

Also useful for methods where different subclasses needs to specialize the behavior.

We've tripped on the method use case before. Let's not repeat that mistake.

# Kevin Smith (12 years ago)

Aside from this confinement issue, all other the advantages that unique symbols have over unique-ish strings seem minor to me. The biggest is default non-enumerability, when we're getting away (admittedly slowly) from enumerability being significant anyway. IMO, if the only advantages of unique symbols over unique-ish strings are these minor ones, then they don't pull their weight.

The fact that, in the context of unique symbols, the unforgability property of the symbol is pointless indicates to me that we might have a mixing of orthogonal concerns.

That leaves default non-enumerability. Consider the fact that object literal methods are enumerable. Why should choosing a "unique name" as opposed to an identifier for a method have any bearing on enumerability?

# Dean Landolt (12 years ago)

On Wed, Jul 31, 2013 at 8:50 AM, Kevin Smith <zenparsing at gmail.com> wrote:

Aside from this confinement issue, all other the advantages that unique symbols have over unique-ish strings seem minor to me. The biggest is default non-enumerability, when we're getting away (admittedly slowly) from enumerability being significant anyway. IMO, if the only advantages of unique symbols over unique-ish strings are these minor ones, then they don't pull their weight.

The fact that, in the context of unique symbols, the unforgability property of the symbol is pointless indicates to me that we might have a mixing of orthogonal concerns.

Unforgability is pointless, sure, but not so fast: as Brendan suggested at a few days back re: MAC addresses and such, you can't ignore the difference between collision-proof and collision-resistant. The difference is identity -- object (and symbol) identity is intrinsic, string identity is extrinsic. If we're talking about keys we're talking about identity -- this is not at all orthagonal.

I'm not arguing that this is enough of a justification for symbols (especially in lieu of privates), but we can't hand-wave this distinction away -- it's essential.

That leaves default non-enumerability. Consider the fact that object literal methods are enumerable. Why should choosing a "unique name" as opposed to an identifier for a method have any bearing on enumerability?

Because GUID-unique-strings are ugly? /troll

I know there's still a ton of unguarded for/in over object keys. I'll admit to using it from time to time -- it's the easiest way to pick up enumerable prototype keys, and plenty safe -- so long as you zealously guard Object.prototype.

I still see the occasional for/in over arrays that would fail hard, but that's harder to defend :)

# Mark S. Miller (12 years ago)

On Tue, Jul 30, 2013 at 10:56 PM, Brendan Eich <brendan at mozilla.com> wrote:

No, "friend" is shared between two classes, no way to make a closure per instance extending over both constructors. Pretend the module above is an IIFE.

You're missing my point. My point is independent of whether there are two classes or one in the scope of your friend declaration. For simplicity let's say there's only class A. this binding only helps when a method is applied to its bound this, not to an argument.

  • It does not enable an instance of A to recognize that another instance of A is an A.
  • It does not avoid the storage cost of objects-as-closures, since you still need a function object per method per instance.

Ok, forget instanceof. With this-binding all around, what's the leak? More generally, are you arguing that leaks are hard to avoid, so we need private fields instead? That fits the relationship vs. unique symbol dichotomy.

If there is in fact no practical scenario for using unique symbols for privacy -- which is what we're exploring above -- then yes.

# Mark S. Miller (12 years ago)

On Wed, Jul 31, 2013 at 5:47 AM, Erik Arvidsson <arv at google.com> wrote:

Also useful for methods where different subclasses needs to specialize the behavior.

We've tripped on the method use case before. Let's not repeat that mistake.

Hi Erik, I'm missing your point. Could you give an example? Thanks.

# Mark S. Miller (12 years ago)

On Wed, Jul 31, 2013 at 6:24 AM, Dean Landolt <dean at deanlandolt.com> wrote:

Unforgability is pointless, sure, but not so fast: as Brendan suggested at a few days back re: MAC addresses

Don't ever use MAC addresses, dates, times, positions, etc, as sources of uniqueness. What a collision resistant string? Use 128 bits of entropy. You'll get an accidental collision of these with the same rarity as you will for two unique symbols because of an undetected memory error.

and such, you can't ignore the difference between collision-proof and collision-resistant. The difference is identity -- object (and symbol) identity is intrinsic, string identity is extrinsic. If we're talking about keys we're talking about identity -- this is not at all orthagonal.

In thinking about this, I become ever more puzzled about the versioning and inter-realm problems for user-defined unique symbols -- I think it may be a train wreck. Scenario: Library W version 1.1 defines and uses a unique symbol @foo which is loaded into realm A. Library W version 1.2 purposely intends to continue to define and use the "same" unique symbol @foo, so that W1.2 code can successfully handle instances of W1.1 code. Library W1.2 is loaded into realm B. The two realms come into contact, and objects from the two W's come into contact. How did they both coordinate to define and use the same @foo symbol?

Because GUID-unique-strings are ugly? /troll

That's why you refer to them symbolically. Just like we write Math.PI in good code, rather than 3.14159...

I know there's still a ton of unguarded for/in over object keys. I'll admit to using it from time to time -- it's the easiest way to pick up enumerable prototype keys, and plenty safe -- so long as you zealously guard Object.prototype.

I still see the occasional for/in over arrays that would fail hard, but that's harder to defend :)

This is the enumerability issue which I already acknowledged, right? Is there anything more to this?

# Erik Arvidsson (12 years ago)

On Wed, Jul 31, 2013 at 10:38 AM, Mark S. Miller <erights at google.com> wrote:

Hi Erik, I'm missing your point. Could you give an example? Thanks.

I was thinking private unique symbols. I see now that I misunderstood what Brendan wrote.

Brendan, could you expand those ellipses in your example?

# Brendan Eich (12 years ago)

Mark S. Miller wrote:

You're missing my point. My point is independent of whether there are two classes or one in the scope of your friend declaration. For simplicity let's say there's only class A. this binding only helps when a method is applied to its bound this, not to an argument.

  • It does not enable an instance of A to recognize that another instance of A is an A.
  • It does not avoid the storage cost of objects-as-closures, since you still need a function object per method per instance.

Sorry for being unclear -- my fault for not taking the time to develop the example. An example would have to avoid closure pattern even coming to mind, since I don't think it is relevant. The general problem is making a non-colliding name that can be used in two disjoint scopes, on objects of known provenance.

# Brendan Eich (12 years ago)

Mark S. Miller wrote:

Don't ever use MAC addresses, dates, times, positions, etc, as sources of uniqueness.

uuidgen implementations have used MAC addresses in the past, which I believe led to a public collision.

What a collision resistant string? Use 128 bits of entropy. You'll get an accidental collision of these with the same rarity as you will for two unique symbols because of an undetected memory error.

Wait, what? An "undetected memory error" meaning a GC bug where a symbol is freed before it is dead and reincarnated as another symbol? That is rare enough that I don't believe you (or anyone) can say colliisions are as rare. We are arguing quality-of-implementation here.

Gathering entropy enough to make a UUID is work. A crypto module's RBG should be up to it. Browsers have those, but we haven't yet required any such thing in ECMA-262, and I expect some implementations will be crypto-module-free and cheese out on the quality (where they wouldn't ship unpatched memory safety bugs!). This is worth a discussion: do we require an RBG with the right quality in normative words in ES6?

# Brendan Eich (12 years ago)

Erik Arvidsson wrote:

Brendan, could you expand those ellipses in your example?

I was thinking the same thing and fell into the "unique scope-confined" trap. I agree it's too easy to leak non-private symbols via reflection, but it wasn't clear Mark was making that point (closure-pattern didn't seem relevant, still doesn't...).

# Bill Frantz (12 years ago)

On 7/31/13 at 8:35 AM, brendan at mozilla.com (Brendan Eich) wrote:

uuidgen implementations have used MAC addresses in the past, which I believe led to a public collision.

In 1998 we (Electric Communities) discovered that people using AOL software to access the internet were all assigned the same MAC address. Using timing of UI events is much better.

# Dean Landolt (12 years ago)

On Wed, Jul 31, 2013 at 10:50 AM, Mark S. Miller <erights at google.com> wrote:

In thinking about this, I become ever more puzzled about the versioning and inter-realm problems for user-defined unique symbols -- I think it may be a train wreck. Scenario: Library W version 1.1 defines and uses a unique symbol @foo which is loaded into realm A. Library W version 1.2 purposely intends to continue to define and use the "same" unique symbol @foo, so that W1.2 code can successfully handle instances of W1.1 code. Library W1.2 is loaded into realm B. The two realms come into contact, and objects from the two W's come into contact. How did they both coordinate to define and use the same @foo symbol?

I responded in separate thread, but I'd add that this problem exists regardless of the mechanism chosen for doing unique. It's not a problem of symbols but of intrinsic object identity. This is why I believe modeling symbols as stateless frozen objects is most sensible and correct thing.

That's why you refer to them symbolically. Just like we write Math.PI in good code, rather than 3.14159...

Agreed -- I was mostly joking. But there's a reason the proposal called for a string prefix -- they will be reflected in the raw. Unlike Math.PI, this raw value is meaningless.

This is the enumerability issue which I already acknowledged, right? Is there anything more to this?

I was responding directly to Kevin's comment:

That leaves default non-enumerability. Consider the fact that object literal methods are enumerable. Why should choosing a "unique name" as opposed to an identifier for a method have any bearing on enumerability?

I was pointing out the very real hazard that exists in code which wouldn't be considered objectively bad. To be explicit, I'm claiming that for/in over object keys can be the Right Thing in cases where you want all enumerable keys up through the prototype. If unique symbols aren't enumerable and the platform demands any of them on Object.prototype this will introduce subtle run-time breakages at least as badly as "null" typeof. Even if es6 avoids them on Object.prototype who's to say they won't be needed in later versions? This will bite eventually.

# Mark S. Miller (12 years ago)

On Wed, Jul 31, 2013 at 8:35 AM, Brendan Eich <brendan at mozilla.com> wrote:

Wait, what? An "undetected memory error" meaning a GC bug where a symbol is freed before it is dead and reincarnated as another symbol? That is rare enough that I don't believe you (or anyone) can say colliisions are as rare. We are arguing quality-of-implementation here.

I'm not talking about the probability of a software bug. We all write perfect software so the probability of such bugs is zero -- I agree.

No, I'm talking about the probability of an undetected hardware failure, such as one caused by cosmic rays or other physical causes. All digital hardware rests on analog hardware which rests on quantum mechanical hardware. There ain't nothing else. Our digital hardware is all built to keep the error rate below some threshold considered acceptable. For any hardware we can afford, that error rate threshold is also not violated by accidental collisions between randomly chosen 128 bit keys. (Unless we're worried about birthday effect collisions, as perhaps we should be, in which case we should go to 256 bits of entropy.)

Gathering entropy enough to make a UUID is work. A crypto module's RBG should be up to it. Browsers have those, but we haven't yet required any such thing in ECMA-262, and I expect some implementations will be crypto-module-free and cheese out on the quality (where they wouldn't ship unpatched memory safety bugs!). This is worth a discussion: do we require an RBG with the right quality in normative words in ES6?

A good point. We should indeed discuss the costs of adding this requirement.

# Brendan Eich (12 years ago)

Mark S. Miller wrote:

I'm not talking about the probability of a software bug. We all write perfect software so the probability of such bugs is zero -- I agree.

Heh. My point was the probability of each bad thing (memory safety bug, uuid collision) is probably higher than we think but I have no data.

No, I'm talking about the probability of an undetected hardware failure, such as one caused by cosmic rays or other physical causes. All digital hardware rests on analog hardware which rests on quantum mechanical hardware. There ain't nothing else. Our digital hardware is all built to keep the error rate below some threshold considered acceptable. For any hardware we can afford, that error rate threshold is also not violated by accidental collisions between randomly chosen 128 bit keys. (Unless we're worried about birthday effect collisions, as perhaps we should be, in which case we should go to 256 bits of entropy.)

A crypto-grade RBG should be enough, I agree.

A good point. We should indeed discuss the costs of adding this requirement.

Ok. I think it's going to be a problem for "tiny" embeddings of ECMA-262 implementations (Japanese smart TVs? Maybe these are "legacy", the "compact profile", even). We need to cast a wide net.

# Brendan Eich (12 years ago)

Brendan Eich wrote:

Ok. I think it's going to be a problem for "tiny" embeddings of ECMA-262 implementations (Japanese smart TVs? Maybe these are "legacy", the "compact profile", even). We need to cast a wide net.

And the meta-hazard here is a race to the bottom. If systems interop and some generate worse UUIDs than others, a corollary of Gresham's Law will probably kick in.

# Till Schneidereit (12 years ago)

On Wed, Jul 31, 2013 at 6:21 PM, Dean Landolt <dean at deanlandolt.com> wrote:

That leaves default non-enumerability. Consider the fact that object literal methods are enumerable. Why should choosing a "unique name" as opposed to an identifier for a method have any bearing on enumerability?

I was pointing out the very real hazard that exists in code which wouldn't be considered objectively bad. To be explicit, I'm claiming that for/in over object keys can be the Right Thing in cases where you want all enumerable keys up through the prototype. If unique symbols aren't enumerable and the platform demands any of them on Object.prototype this will introduce subtle run-time breakages at least as badly as "null" typeof. Even if es6 avoids them on Object.prototype who's to say they won't be needed in later versions? This will bite eventually.

I agree that this is something we should care about.

Would implicitly treating identifiers that have the right format as symbols solve this? I.e., instead of having to explicitly create a unique symbol, just using a string of the right ugly format makes the engine treat fields with that identifier as the key as non-enumerable.

# Mark S. Miller (12 years ago)

On Wed, Jul 31, 2013 at 9:42 AM, Mark S. Miller <erights at google.com> wrote:

(Unless we're worried about birthday effect collisions, as perhaps we should be, in which case we should go to 256 bits of entropy.)

I retract the parenthetical. For this use case a birthday effect collision cannot be relevant.

# Kevin Smith (12 years ago)

Agreed -- I was mostly joking. But there's a reason the proposal called for a string prefix -- they will be reflected in the raw. Unlike Math.PI, this raw value is meaningless.

Yes - a minor issue with unique strings is that you will see distractingly ugly property names in your debugger. More in the other thread...

I was pointing out the very real hazard that exists in code which wouldn't be considered objectively bad. To be explicit, I'm claiming that for/in over object keys can be the Right Thing in cases where you want all enumerable keys up through the prototype. If unique symbols aren't enumerable and the platform demands any of them on Object.prototype this will introduce subtle run-time breakages at least as badly as "null" typeof. Even if es6 avoids them on Object.prototype who's to say they won't be needed in later versions? This will bite eventually.

Any such unique property names defined on Object.prototype in hypothetical future ES versions would undoubtably be specified as non-enumerable, just like the current string-named properties.

# Domenic Denicola (12 years ago)

From: Erik Arvidsson [erik.arvidsson at gmail.com]

We went through the exercise of only having private symbols but it lead to some issues. Here is one that we identified.

Lets assume we use a private symbol for the @@iterator. The symbol can still be checked because anyone that has access to the right module can get it. It is also important that a proxy for an object, O, is not invoked when you do O[privateSymbol]. This means that it is not possible to create an iterable proxy object, since no trap on the proxy is invoked.

I know the answer will be obvious when I see it, but I can't quite remember ... why is it important that O[privateSymbol] not invoke the proxy?

# Brandon Benvie (12 years ago)

On 8/2/2013 1:02 PM, Domenic Denicola wrote:

I know the answer will be obvious when I see it, but I can't quite remember ... why is it important that O[privateSymbol] not invoke the proxy?

That would leak the Symbol to the Proxy and then private Symbols wouldn't carry a guarantee of security. That's the only difference between private Symbols and unique Symbols.

# Domenic Denicola (12 years ago)

From: Brandon Benvie [bbenvie at mozilla.com]

That would leak the Symbol to the Proxy and then private Symbols wouldn't carry a guarantee of security. That's the only difference between private Symbols and unique Symbols.

Right, I thought about that, but I am still not quite clear on what the attack is here. From an ocap sense, it feels like you're handing off the private symbol to the proxy, which is just like exporting it from your module or passing it to a function. Why should the proxy not have access to something that you gave it?

The attacks I normally consider public symbols vulnerable to are of the form:

module "foo" {
  const public = Symbol();

  export default {
    [public]: 10
  };
}

module "bar" {
  import foo from "foo";
  // Nobody gave me access to the `public` symbol, but I can still do:
  const public = Object.getOwnPropertyKeys(foo)[0];
  // Now I can modify the exported object:
  foo[public] = 20;
}

What would the similar attack code look like for a proxy?

# Brendan Eich (12 years ago)

Practically speaking, given dynamic-this-binding by default in JS, it's too easy to access a foreign object with an important name (private symbol in the hypothesis). It will happen. You will leak it. It can then be used to attack you.

# Tab Atkins Jr. (12 years ago)

On Fri, Aug 2, 2013 at 1:15 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

From: Brandon Benvie [bbenvie at mozilla.com]

That would leak the Symbol to the Proxy and then private Symbols wouldn't carry a guarantee of security. That's the only difference between private Symbols and unique Symbols.

Right, I thought about that, but I am still not quite clear on what the attack is here. From an ocap sense, it feels like you're handing off the private symbol to the proxy, which is just like exporting it from your module or passing it to a function. Why should the proxy not have access to something that you gave it?

The issue is that you may not know the proxy is there. Someone constructs an object of your class, then wraps it in a proxy and passes it into one of your methods. You, assuming it's a real member of your class, talk at it via private symbols to fiddle with the internal state. The proxy intercepts those, and now has access to the internal object state that it wasn't supposed to have.

This is very different from explicitly handing the private symbols to something else.

The attacks I normally consider public symbols vulnerable to are of the form:

module "foo" {
  const public = Symbol();

  export default {
    [public]: 10
  };
}

module "bar" {
  import foo from "foo";
  // Nobody gave me access to the `public` symbol, but I can still do:
  const public = Object.getOwnPropertyKeys(foo)[0];
  // Now I can modify the exported object:
  foo[public] = 20;
}

Private symbols don't show up in getOwnPropertyKeys(), I believe. (Otherwise, you're right, there's no concern with leaking them to proxies, because they'd be auto-leaked to the world by default anyway.)

# Brandon Benvie (12 years ago)

The problem is methods acting on a Proxy this value could leak the Symbol:

module "foo" {
   const secret = Symbol();
   export default class Foo {
     constructor(){
       this[secret] = Math.random();
     }
     increment(){
       this[secret]++;
     }
   }
}

module "bar" {
   import Foo from "foo";

   var secret;

   new Proxy(new Foo(), {
     get(target, key, receiver){
       if (typeof key === 'symbol') {
         secret = key;
       }
       return Reflect.get(target, key, receiver);
     }
   }).increment();

   console.log(secret); // should be the Symbol here
}
# Erik Arvidsson (12 years ago)

On Fri, Aug 2, 2013 at 4:02 PM, Domenic Denicola <domenic at domenicdenicola.com> wrote:

I know the answer will be obvious when I see it, but I can't quite remember ... why is it important that O[privateSymbol] not invoke the proxy?

We don't want to leak the privateSymbol to a proxy.

module 'foo' {
  var privateSymbol = ...;
  export function tag(object) {
    object[privateSymbol] = true;
  }
  export function hasTag(object) {
    return !!object[privateSymbol];
  }
}

If someone passes a proxy into tag/hasTag the privateSymbol object must not be passed to the proxy handler.

# David Bruant (12 years ago)

Le 02/08/2013 22:18, Brendan Eich a écrit :

Practically speaking, given dynamic-this-binding by default in JS, it's too easy to access a foreign object with an important name (private symbol in the hypothesis). It will happen. You will leak it. It can then be used to attack you.

Sketched a proposal for functions to defend themselves over at esdiscuss/2013-July/032370 Class syntax could enable it by default.

Probably not perfect, but seems like it could work. At least, it balances out both proxies and functions ability to defend against one another.

# Domenic Denicola (12 years ago)

Thanks Brandon. As I expected, obvious once you see it. Hopefully my learning experience was helpful to other observers too :).

# Brendan Eich (12 years ago)

David Bruant wrote:

Probably not perfect, but seems like it could work.

We <3 "perfect is enemy of good" as admonition. Also Pascal's "I would have written a shorter letter if I had more time."

However, leak hazard likelihood is never close enough to zero. This means we can't add more strong-this-binding or other techniques and make a wish. This is a human-factors / phenomenology->likelihood problem.