domenic / proposal-blocks

Former home of a proposal for a new syntactic construct for serializable blocks of JavaScript code
215 stars 5 forks source link

maybe rephrase in terms of mobile functions #23

Open mikesamuel opened 6 years ago

mikesamuel commented 6 years ago

I think the interface part of the problem can be phrased in terms of mobile functions.

"Confined mobile functions" explains the terminology.

A function can be sent over a channel and at the receiving end it can be applied to a locally provided argument to obtain a result.

To fit this into JavaScript, we could define two new methods on Function.

Function.makeMobile(
    state, fn,
    packer = (x) => new TextEncoder().encode(JSON.stringify(x)),
    unpacker = (globals, x) => globals.JSON.parse(new globals.TextDecoder().decode(x))
    )
Function.importMobile(mfn)

To apply this to the blöck example, rewrite the code you want to be mobile as a lambda so that the fetch call introduces no free variable.

Function.makeMobile(
    {},
    globals => {
      const res = await globals.fetch("people.json");
      const json = await res.json();
      return json[2].firstName;
    });

and for the use case of blöcks that capture and clone their environment:

const result = await worker<endpoint>{|
  const res = await fetch(endpoint); // OK to use now
  const json = await res.json();

  return json[2].firstName;
|};

becomes

const result = await worker(Function.makeMobile(
    { endpoint },
    (globals, captured) => {
      const res = await globals.fetch(captured.endpoint);
      const json = await res.json();
      return json[2].firstName;
    }));

The { endpoint } provides the same cues as the <endpoint> mechanism.

One can override how cloning happens by specifying different packer/unpackers. For example, one could use a packer that calls JSON.stringify with a replacer that tries to make functions mobile.