Agoric / agoric-sdk

monorepo for the Agoric Javascript smart contract platform
Apache License 2.0
325 stars 205 forks source link

Allowing getters in serialization #826

Open DavidBruant opened 4 years ago

DavidBruant commented 4 years ago

I'm drafting an idea following https://github.com/Agoric/agoric-sdk/issues/818#issuecomment-606915210

Problem

Currently, @agoric/marshal only allows for "all properties are methods" (pass by presence) or "all properties are data" (pass by copy) This directly affects API design of Zoe and ERTP which objects must be all-methods or all-data. This makes the APIs sometimes look not very JS-idiomatic

Solutions

Eventually

There is a solution coming "eventually (not soon)" where data and functions can be mixed

Idea that might be achievable sooner

A solution i'm imagining would be to consider allowing for getters/setters and serializing them as functions (likely with additional metadata to distinguish them from methods). This way the two object categories would be "all properties are methods or getter" (pass by presence) or "all properties are data" (pass by copy)

If this was possible, this would allow for data-looking properties in the Zoe and ERTP APIs. Objects that are currently all-methods could have data-looking properties.

One major difference would be that objects that are currently all-data (like the redemption object) for which we want to add methods (like cancel). These objects are currently all-data and pass-by-copy and data properties would need to be transformed to getter and they would become pass-by-presence

When the "eventually" becomes reality, the getters can be removed, the APIs and their usage remain untouched and objects that had become pass-by-presence temporarily can go back to pass-by-copy (or a mixed thing i imagine)

This is meant to be a temporary hack to make exposed ERTP and Zoe APIs more idiomatic and less awkward

Evaluation

I've tried to look into the code that serializes and i have not understood yet where the current all-methods-or-all-data limitation matters, so i haven't been able to evaluate whether the idea i'm exposing here is possible at all or relevant or can be achieved significantly sooner than the eventual solution

warner commented 4 years ago

Hm. If I have an object with a method foo() and a getter get bar(), then locally I can do x.foo() or bar = x.bar (or x~.foo()). If I send this object over the wire and it arrives on the remote side as y, then that side can invoke y~.foo(). Would we want the remote side to be able to do bar = y.bar to invoke the getter? That sounds like a synchronous call that requires an asynchronous message to produce a result, which can't work.

I've seen a syntax for async property lookup (maybe x~.bar, without the parenthesis, or maybe it was x~.['bar'] or something?), but it's very visibly not a normal property fetch.

What I remember about the methods-or-data limitation was that we want all instances of a pass-by-reference object to behave identically (and have the same === object identity), and we want all copies of a pass-by-copy object to have the same data. Adding passable data to a pass-by-reference object that might change from one act of serialization to the next would break the first property, and I think we enacted the other rule to make it symmetric.

katelynsills commented 4 years ago

Removing Zoe and ERTP labels