Unique String Values: Gensym for JavaScript

Proposal by Allen Wirfs-Brock
An alternative to the revised private_names proposal by Allen Wirfs-Brock
and the original names proposal by Dave Herman and Sam Tobin-Hochstadt .

In existing ECMAScript, string values are distinguished solely based upon their specific ordered sequence of characters. Two strings that have the same sequence of characters are considered to be the same value, even though they originate at different points in a program or exist as distinct implementation level entities. Unique strings extends the ECMAScript string type to also include the concept of distinct strings values that may have identical character sequences.

These values are similar, in concept, to the unique symbols generated by the gensym function in Lisp and other similar languages. They are useful for creating unique property names that are guaranteed to be different from any other property name that has or in the future may be created.

Changes to the ECMAScript String Data Type

Section 8.4 of the ECMAScript specification defines a string to be finite ordered sequence of 16-bit unsigned integer character values. That definition is extended as follows:

Each string value contains a immutable Boolean value named [[Secret]] and an immutable integer value named [[UniqueId]]. Just like a string’s character sequence, the values of [[Secret]] and [[UniqueId]] are set during the creation of a string value and may not be subsequently modified. Unless other specified, each string value is created with false as its [[Secret]] and 0 as its [[UniqueId]]. In particular, the SV of string literals (7.8.4) have the default values for [[Secret]] and [[UniqueId]]. In the rest of the specification the term Unique String is used to mean a string values whose [[UniqueId]] value is non-zero. The term Private String is used to mean a string values whose [[UniqueId]] value is non-zero and whose ‘[[Secret]] value is true. String values are never created with both a [[UniqueId]] value of zero and a ‘[[Secret]] value that is true.

Note [[Secret]] and [[UniqueId]] are specification devices. They need not literally exist within an implementation as long as the observable behavior of the implementation matches the observable characteristics of this specification.

Changes to ECMAScript Operations on String Values

This extension does not change the semantics of any ECMAScript operations upon string values other than those explicitly identified in this specification. The values of [[Secret]] and [[UniqueId]] have no effect upon such string operations unless explicitly identified by this specification as having an effect.

Changes to Property Access Abstract Operations

In some cases the current ECMAScript specification is imprecise concerning how a string value is used as a name for accessing or creating an object property. The following clarification are made as part of this proposal:

8.12.1 [[GetOwnProperty]]

Replace:
1. If O doesn’t have an own property with name P, return undefined.
with:
1. If O dosn’t have an own property whose name is the SameValue as P, return undefined.

Replace:
3. Let X be O‘s own property named P.
with:
3. Let X be O‘s own property whose name is the SameValue as P.

8.12.7 [[Delete]]

Replace:
3.a. Remove the own property with name P from O.
with:
3.a. Remove the own property whose name is the SameValue as P from O.

8.12.9 [[DefineOwnProperty]]

Replace:
12. For each attribute field of Desc that is present, set the corresponding named attribute of the property named P of object O to the value of the field.
with:
12. For each attribute field of Desc that is present, set the corresponding named attribute of the property of object O whose name is the SameValue as P to the value of the field.

Changes to Type Conversion and Testing

Note that this proposal does not modify the Abstract Relational Comparison Algorithm or the Abstract Equality Comparison Algorithm.

9.12 The SameValue Algorithm

Replace:
5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise return false.
with:
5. If Type(x) is String, then return true if x and y have the same [[UniqueId]] value and have exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise return false.

Note that if the proposed egal operator should use this modified specification of the SameValue Algorithm.

11.9.6 The Strict Equality Algorithm

Replace:
5. If Type(x) is String, then return true if x and y are exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise return false.
with:
5. If Type(x) is String, then return true if x and y have the same [[UniqueId]] value and have exactly the same sequence of characters (same length and same characters in corresponding positions); otherwise return false.

Creating Unique String Values

String values with non-zero [[UniqueId]] values and possibly a true [[Secret]] are created using the following new built-in property of the String Constructor. These are the only way that new Unique String values can be created. It is impossible to synthesis an already existing Unique String value using a String literal or in any other manner.

15.5.3.3 String.unique(value)

If value is not present let value be the empty string. If the type of value is not String let value be the result of ToString(value). Returns a String value containing the same sequence of characters as value. The value of [[UniqueId]] for the returned string is set to an integer that is 1 greater than any previous value that has been assigned to any string’s [[UniqueId]]. The value of [[Secret]] for the returned string is set to false.

This function most closely corresponds to the Lisp gensym function. The value is provided primarily for debugging purposes and can be omitted.

15.5.3.4 String.secret(value)

If value is not present let value be the empty string. If the type of value is not String let value be the result of ToString(value). Returns a String value containing the same sequence of characters as value. The value of [[UniqueId]] for the returned string is set to an integer that is 1 greater than any previous value that has been assigned to any string’s [[UniqueId]]. The value of [[Secret]] for the returned string is set to true.

String.secret operates exactly like String.unique except that the [[Secret]] internal property of returned string is set to true. The [[Secret]] internal property is used by reflective operations that expose property names to limit the exposure of such names. Code can only directly gain access via reflection to a secret string valued property name if it already has access to that secret string value.

Using Unique String Values as Property Names

Because unique string values are real string values, they may be used in any context where a string is required including as property names. However, such properties can only be created and accessed using bracket notation or reflection operations. For example, a property with a unique string name might be added to an object as follows:

var x = String.unique();  //create a new Unique Name value.
var obj = {};
obj[x] = 1;
print(obj[x]);  //prints 1

Because the SameValue algorithm is used for property lookup distinct unique string values designate separate properties even when the unique strings have the same character sequences:

var x = String.unique("x");  //create a new Unique String value.
var x2 = String.unique("x"); //create another  Unique String value.
var obj = {};
obj[x] = 1;
obj[x2] = 2
print(obj[x]+obj[x2]);  //prints 3

Property named using unique strings are also distinct from properties accessed using normal strings or dot notation:

var x = String.unique("x");  //create a new Unique Name value.
var obj = {};
obj[x] = 1;
print(obj["x"]);  //prints undefined
print(obj.x);     //prints undefined

The use of an unique string (even those with a true value for [[Secret]]) has no direct effect on the enumerablity of properties. If it is desired that a unique name not be exposed via for-in enumeration then its property must be explicitly made non-enumerable:

var y = String.secret();  //create a new Unique strng value.
var obj = {a:1};
Object.defineProperty(obj,y,{value: 2, enumerable: false}}
for (var p in obj) print(p);  //prints "a"

Special Handling of Unique Strings Where [[Secret]] is true

Setting [[Secret]] to true for a unique string prevents that string from being directly exposed using certain reflective operations. Instead, in those situations, a special secrecy wrapper object is used instead of a unique string value.

Secrecy Wrappers

A Secrecy Wrapper is an object with an [[Hidden]] internal property and the following two methods. Secret Wrapper objects are always created as frozen objects.

<secrecy wrapper>.sameSecret(obj)

If either the this object or the value of obj does not have a [[Hidden]] internal property return false. Otherwise, return the result of applying the SameValue algorithm to the values of the [[Hidden]] internal property of the this object and obj.

<secrecy wrapper>.isIt(value)

If the this object does not have a [[Hidden]] internal property throw TypeError exception. Otherwise, return the result of applying the SameValue algorithm to the value of the [[Hidden]] internal properties of the this object and the value of obj.

Producing Secrecy Wrappers

Secrecy wrapper are used instead of string values in the following situations:

  • In place of any string value whose [[Secret]] value is true that would be contained in the array returned by Object.getOwnPropertyNames.
  • Any name argument passed to a Proxy trap handler where the name is a string value whose [[Secret]] value is true.

Unique Strings and WeakMaps

Unique Strings are explicitly created and existing or previously existing Unique Strings can not be re-synthesized. Unlike other string values they are subject to garbage collection. Because of this, it is useful to use them as keys of WeakMaps. The weak maps proposal is extended to allow Unique Strings to be used as WeakMap keys.

 
strawman/unique_string_values.txt · Last modified: 2011/05/18 00:55 by allen
 
Recent changes RSS feed Creative Commons License Donate Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki