Skip to content

Commit e3abbc0

Browse files
authored
add new motivating usecases (#3)
* add new motivating usecases * remove what seems like a leftover or a deviation from interface described earlier from the example * add reference to importHook
1 parent d5eabf9 commit e3abbc0

1 file changed

Lines changed: 53 additions & 31 deletions

File tree

README.md

Lines changed: 53 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,11 @@
33
Stage: To be presented for advancement to stage 1 at a future TC-39 plenary.
44

55
Champions:
6-
- Zbyszek Tenerowicz (ZB), Consensys, @naugtur
7-
- Kris Kowal (KKL), Agoric, @kriskowal
8-
- Richard Gibson (RGN), Agoric @gibson042
9-
- Mark S. Miller (MM), Agoric @erights
6+
7+
- Zbyszek Tenerowicz (ZTZ), Consensys, @naugtur
8+
- Kris Kowal (KKL), Agoric, @kriskowal
9+
- Richard Gibson (RGN), Agoric, @gibson042
10+
- Mark S. Miller (MM), Agoric, @erights
1011

1112
## Synopsis
1213

@@ -44,16 +45,16 @@ interface Global {
4445
Global: typeof Global,
4546
Function: typeof Function,
4647
eval: typeof eval,
47-
48+
4849
// and ...globalThis[...keys]
4950
}
5051
```
5152

5253
```js
5354
new globalThis.Global({
54-
keys: Reflect.ownKeys(globalThis), // default behavior equivalent
55-
importHook,
56-
importMeta,
55+
keys: Reflect.ownKeys(globalThis),
56+
importHook,
57+
importMeta,
5758
});
5859
```
5960

@@ -71,7 +72,7 @@ Produces a _global_ with fresh:
7172
in the evaluated code
7273
- All other function constructors, which can be accessed through `eval` and
7374
their corresponding, undeniable syntax, like `global.eval('async () =>
74-
{}').constructor`.
75+
{}').constructor`.
7576

7677
The global does not require a fresh `ModuleSource` because
7778
the source is paired with the global by use of dynamic `import` in global evaluation,
@@ -87,12 +88,17 @@ const thatGlobal = new globalThis.Global({
8788
thatGlobal.eval !== thisGlobal.eval;
8889
thatGlobal.Global !== thisGlobal.Global;
8990
thatGlobal.Function !== thisGlobal.Function;
90-
thatGlobal.eval('Object.getPrototypeOf(async () => {})') !== Object.getPrototypeOf(async () => {});
91-
thatGlobal.eval('Object.getPrototypeOf(function *() {})') !== Object.getPrototypeOf(function *() {});
92-
thatGlobal.eval('Object.getPrototypeOf(async function *() {})') !== Object.getPrototypeOf(async function *() {});
93-
const source = new ModuleSource('export default {}');
94-
(await thatGlobal.eval('(...args) => import(...args)')(source)) !== (await import(source));
91+
thatGlobal.eval("Object.getPrototypeOf(async () => {})") !==
92+
Object.getPrototypeOf(async () => {});
93+
thatGlobal.eval("Object.getPrototypeOf(function *() {})") !==
94+
Object.getPrototypeOf(function* () {});
95+
thatGlobal.eval("Object.getPrototypeOf(async function *() {})") !==
96+
Object.getPrototypeOf(async function* () {});
97+
const source = new ModuleSource("export default {}");
98+
(await thatGlobal.eval("(...args) => import(...args)")(source)) !==
99+
(await import(source));
95100
thatGlobal.ModuleSource === thisGlobal.ModuleSource;
101+
thatGlobal.Array === thisGlobal.Array;
96102
thatGlobal.x === thisGlobal.x;
97103
```
98104

@@ -117,20 +123,13 @@ which leaks for the cases of syntactically undeniable Realm-specific intrinsics
117123
like the `AsyncFunction` constructor and prototype, and requires the
118124
implementer to be vigilant to the extent that they graft every intrinsic from
119125
one realm to another.
120-
We have found such arrangements to be fragile and leaky.
126+
We have found such arrangements to be fragile and leaky. Also costly in memory efficiency and developer time.
121127

122128
New `Global` provide an alternate solution: evaluate modules or scripts in a
123129
separate global scope with shared intrinsics.
124130

125131
```js
126-
const dslGlobal = const new Global({
127-
globalThis: {
128-
__proto__: globalThis,
129-
describe,
130-
before,
131-
after,
132-
}
133-
});
132+
const dslGlobal = const new Global();
134133
dslGlobal.describe = () => {}
135134
dslGlobal.before = () => {}
136135
dslGlobal.after = () => {};
@@ -141,7 +140,7 @@ await dslGlobal.eval('s => import(s)')(source);
141140

142141
In this example, only the entrypoint module for the DSL sees additional
143142
globals.
144-
The `source` adopts the import hook associatd with `dslGlobal` by
143+
The `source` adopts the import hook associated with `dslGlobal` by
145144
virtue of using the `dslGlobal`'s dynamic `import`.
146145
Current DSLs cannot execute concurrently or depend on dynamic scope to track
147146
the entrypoint that called each DSL verb.
@@ -172,6 +171,29 @@ TC53][tc53], do not have an origin on which to build a same-origin-policy, and
172171
have elected to build their security model on isolated evaluators, through the
173172
high-level Compartment interface.
174173

174+
### Isolating unreliable code
175+
176+
The way modern software is composed has already undermined the validity of the assumption that every author participating has their intentions well aligned for the benefit of the software working correctly. A whole new level of unreliability is now added with the popularity of _coding agents_ and _vibe coding_ where creating syntactically valid but effectively unpredictable JavaScript and integrating it into existing software to check whether it seems to implement the desired functionality is becoming a popular way of building software.
177+
178+
It is not an entirely new concern, as test runners have been concerned with isolating test cases to avoid them relying on global side-effects of other test cases. It is now a concern for a much wider audience with more at stake.
179+
180+
With `Global` constructor comes the ability to isolate fragments of the application in a way that unreliable code cannot rely on shared global state without the maintainer of the software knowing about it.
181+
AI generated sources from independently working agents can come with colliding names for global variables to use and may need separate global scopes to collaborate or coexist. Similarly a misguided attempt at an inline polyfill by an AI or a package author could be prevented by freezing the contents of a new global in which the unreliable code subsequently runs.
182+
Using a new global instead of a new Realm avoids the issues like identity discontinuity impeding the composition of software where function calls need to happen across the isolated and non-isolated code.
183+
184+
The isolation use case depends also on the interaction with `importHook` and `ModuleSource` as described in
185+
186+
https://github.com/endojs/proposal-import-hook/?tab=readme-ov-file#new-global
187+
188+
189+
### Incremental or in-context execution
190+
191+
There are tools that currently use much more complex and costly mechanisms (similar to the ones described in [Domain Specific Languages](#domain-specific-languages) among other) to provide the ability to execute fragments of JavaScript code in a very specific context of the tool.
192+
193+
That includes REPLs, inline code execution results in editors (eg. [Quokka.js](https://quokkajs.com/)) and various use cases of IDEs in the browser.
194+
195+
Maintaining the global state between executions of user-provided code snippets would benefit from a `Global` constructor.
196+
175197
## Intersection Semantics
176198

177199
### Shared Structs
@@ -184,7 +206,7 @@ share any undeniable mutable state.
184206

185207
## Design Questions
186208

187-
### prototype chain in the browser
209+
### Prototype chain in the browser
188210

189211
`globalThis` in the browser has a non-trivial prototype chain for some Window
190212
API functionality and events.
@@ -196,13 +218,13 @@ API functionality and events.
196218
to invoke it.
197219

198220
```js
199-
globalThis.constructor === Window
200-
const g1 = new Global()
221+
globalThis.constructor === Window;
222+
const g1 = new Global();
201223

202-
g1.globalThis.constructor === Global // would need to be true I suppose
203-
g1.globalThis.constructor === g1.globalThis.Global // definitely not
204-
g1.globalThis.constructor === g1.globalThis.Window // umm...
205-
g1.globalThis.Window === Global // maybe that solves it?
224+
g1.globalThis.constructor === Global; // would need to be true I suppose
225+
g1.globalThis.constructor === g1.globalThis.Global; // definitely not
226+
g1.globalThis.constructor === g1.globalThis.Window; // umm...
227+
g1.globalThis.Window === Global; // maybe that solves it?
206228
```
207229

208230
Meanwhile in Node.js `globalThis.constructor.name === 'Object'`

0 commit comments

Comments
 (0)