Re: [w3ctag/design-reviews] Realms API ECMAScript Proposal (#542)

> 2. The mechanism for how values are passed back and forth seem unclear from our reading. There are mentions of transferrables, but presumable non-transferrable objects are copied in each direction?

Only primitive values are fully transferable. Any try to transfer Non-callable objects will cause an abrupt completion (thrown exception). Callable Objects are internally wrapped into a new exoctic callable, called "Wrapped Function Exotic Object". 

That means, if the importValue or the result of `evaluate` returns a callable object (functions, proxied functions, arrow functions, etc), this callable object is wrapped into this new exotic. The same happens if a wrapped function returns any callable object.

This means, if I have incubator Realm A, and child Realm B, and I inside A I run `B.evaluate('x => x * 2')`, this evaluation will create a new Wrapped Function Exotic Object in Realm A. 

When Realm A calls this new exotic object, it synchronously calls the evaluated arrow function from B, captures the return value, and return it in Realm A.

```js
// Realm A
const B = new Realm();

// Realm B creates an arrow function and returns it
// fn is a Wrapped Exotic object that as an internal [[Wrapped]] containing the arrow function
const fn = B.evaluate('x => x * 2');

// This call will internally call fn.[[Wrapped]](3). The result is a primitive, return it.
fn(3); // 6
```

There is no function unwrapping in user code, and this is a hard requirement to avoid leaking identities.

This means each time I evaluate something that returns the same callable, I always receive a new Wrapped Function Exotic Object.

```js
// Realm A
const B = new Realm();

B.evaluate('globalThis.fn = x => x * 2');

B.evaluate('fn === fn'); // true

const wrapped = B.evaluate('fn');
const wrappedAgain = B.evaluate('fn');

console.log(wrapped === wrappedAgain); // false

wrapped(3); // 6
wrappedAgain(3); // 6, they are both callables from Realm A connected to the same function in Realm B
```

This also means we wrap functions the other way around, with no identification:

```js
// Realm A
const B = new Realm();

B.evaluate('globalThis.fn = x => x * 2');

const wrapped = B.evaluate('fn');

const compare = B.evaluate('callable => callable === fn');
compare(wrapped); // false

const verify = B.evaluate('callable => callable(7)');
verify(wrapped); // 14
```

In the example above, `compare` sends `wrapped` to Realm B, but `wrapped` is once again _wrapped_ as an internal of a new Wrapped Function Exotic Object inside Realm B. It's not unwrapped identifying `fn`.

The `verify` sends `wrapped` to be executed in B and capture it's value. Realm B receives it with the name `callable` and call with the argument 7, returning it back to Realm A's `verify`.



-- 
You are receiving this because you are subscribed to this thread.
Reply to this email directly or view it on GitHub:
https://github.com/w3ctag/design-reviews/issues/542#issuecomment-840871150

Received on Thursday, 13 May 2021 22:28:28 UTC