Skip to content

Commit

Permalink
update to have componentSymbol split out
Browse files Browse the repository at this point in the history
  • Loading branch information
bfarias-godaddy committed May 9, 2018
1 parent e5606a2 commit f64560d
Showing 1 changed file with 46 additions and 6 deletions.
52 changes: 46 additions & 6 deletions compositeKey/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,50 @@
# compositeKey
# compositeKey, compositeSymbol

This proposal seeks to add an API to create composite keys while still allowing the components of the composite key to be GC'd.
This proposal seeks to add APIs to create composite keys while still allowing the components of the composite key to be GC'd.

## API

In all APIs order of arguments is preserved in the path to the key. `compositeKey(a, b)` is different from `compositeKey(b, a)`.

In all APIs at least one component must be a valid `WeakMap` key. This is because the main use case for these APIs is to allow GC to occur when the lifetime of the components is ended.

```mjs
compositeKey(...parts: [...any]) : Object.freeze({__proto__:null})

// if there is only 1 part and it is a string, act the same as Symbol.for
compositeSymbol(...parts: [...any]) : Symbol()
```

## Where will it live

A builtin module; how to import builtin modules TBD based upon current TC39 discussions.

## FAQ

### Why a frozen empty Object?
### Why have both `compositeKey` and `compositeSymbol`?

They are serving two slightly different use cases.

#### `compositeKey`

Allows using a Map/Set/WeakMap to weakly and/or privately associate data with the lifetime of a group of values.

#### `compositeSymbol`

Allows strongly attaching data to an Object that is associtated with a group of values. This API can be roughly recreated by using:

```mjs
let symbols = new WeakMap;
compositeSymbol = (...parts) => {
const key = compositeKey(...parts);
if (!symbols.has(key)) symbols.set(key, Symbol());
return symbols.get(key);
}
```

However, this causes a problem of not being a global cache like `Symbol.for` or `compositeKey` and may cause fragmentation. It also would be ideal to have `compositeSymbol` act like `Symbol.for` in order to reduce total number of possible entries being held onto.

### Why a frozen empty Object for `compositeKey`?

So that properties cannot be added to the object that will leak to the global or can be used as a public side channel.

Expand All @@ -28,9 +64,13 @@ Still up for debate but some TC39 members would like it to be per Realm.

Having it be per Realm allows the key store to be more granular and free up segments as Realms are GC'd, but means that there could be multiple keys that correspond to `compositeKey(A, B)` if you obtain multiple `compositeKey` instances from multiple realms.

Having it be across Realms means that you cannot cause duplicate keys for component parts, and matches with `Symbol.for`. Since the result of `compositeKey` has a null prototype there is not a way to distinguish which Realm the result was first created in.

Currently, this proposal is looking to progress with cross Realm idempotentcy.

### When can the key be GC'd

The path to a key in the key store can be GC'd once any owner of a lifetime in the path is GC'd. This means once any single non-primitive component is GC'd the key cannot be obtained again using `compositeKey`. The key itself is an object subject to normal GC rules and will be removed when it is no longer strongly held.
The path to a key in the key store can be GC'd once any owner of a lifetime in the path is GC'd. This means once any single non-primitive component is GC'd the key cannot be obtained again using these APIs. The key itself is an object subject to normal GC rules and will be removed when it is no longer strongly held.

If you only store keys in `WeakMap`s the key and associated values can be GC'd as soon a component of the key is GC'd.

Expand All @@ -53,6 +93,6 @@ myValues.set(myKey, components);
let [a, b] = myValues.get(myKey);
```

### How can I create an "immortal" composite key composed only of primitives?
### How can I create an "immortal" `compositeKey` composed only of primitives?

You cannot, but you can always use the `compositeKey` function as the first argument when calling `compositeKey` to make a key that is able to be retrieved as long as `compositeKey` is alive.
You cannot since the main use case is to allow GC to occur, but you can always use the `compositeKey` function as the first argument when calling `compositeKey` to make a key that is able to be retrieved as long as `compositeKey` is alive.

0 comments on commit f64560d

Please sign in to comment.