Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement the latest version of the defineKind API #4962

Merged
merged 1 commit into from
Apr 6, 2022

Conversation

FUDCo
Copy link
Contributor

@FUDCo FUDCo commented Mar 30, 2022

This implements the newest version of the defineKind API, as laid out in #4905.

Closes #4905

@FUDCo FUDCo added enhancement New feature or request SwingSet package: SwingSet labels Mar 30, 2022
@FUDCo FUDCo requested a review from warner March 30, 2022 06:40
@FUDCo FUDCo self-assigned this Mar 30, 2022
@FUDCo FUDCo marked this pull request as draft March 30, 2022 06:45
@FUDCo
Copy link
Contributor Author

FUDCo commented Mar 30, 2022

Note: I've marked this as DRAFT because it will not pass CI, because there are a couple of uses of defineKind elsewhere in the source tree that need to be updated to use the new API, and what those uses are doing is complicated and weird and hard to understand. MarkM and I will pair on fixing these on Thursday afternoon, but I wanted to get this PR up so the main substance can be reviewed.

@warner
Copy link
Member

warner commented Mar 30, 2022

Does this also add the crosslinks and unweakables?

@FUDCo
Copy link
Contributor Author

FUDCo commented Mar 30, 2022

Yes. Two separate commits, one for the API overhaul and one for the anti-GC-observability stuff.

dckc added a commit that referenced this pull request Mar 30, 2022
I'm assigned as an owner of #4962 , but I don't see much reason for that. I think the `*` line at the top was intended to match things that don't match other lines, but I don't think it works that way. I think it tags me as an owner of every PR.
@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch 4 times, most recently from e3d5627 to 688718a Compare April 1, 2022 07:35
Copy link
Member

@dckc dckc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I defer to other reviewers.

@@ -411,6 +449,27 @@ export function makeVirtualObjectManager(
}
}

function copyMethods(behaviorTemplate) {
const obj = {};
for (const [name, func] of Object.entries(behaviorTemplate)) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enables Symbol-named methods, yeah? I think we want that, at least in the long run, and anyways Far should be the judge of what keys are allowed, so I think Object.entries is exactly right.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wish. Two factors combine to make this not work well:

  • Object.entries omits non-enumerable properties
  • Object literals with symbol-named properties initialize those properties to be non-enumerable.
> x = {[Symbol.asyncIterator]: () => null}
{ [Symbol(Symbol.asyncIterator)]: [Function: [Symbol.asyncIterator]] }
> Object.entries(x)
[]
> Object.getOwnPropertyDescriptors(x)
{
  [Symbol(Symbol.asyncIterator)]: {
    value: [Function: [Symbol.asyncIterator]],
    writable: true,
    enumerable: true,
    configurable: true
  }
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, forget what I just said. The session I captured above shows that my second bullet is false. The new property is enumerable. But Object.entries omitted it anyway. Which corrected my dim memory: Object.entries only includes string-named properties.

In any case, I agree that Far should know what it accepts and others should make minimal assumptions about what that is. Use Reflect.ownKeys or Object.getOwnPropertyDescriptors in order to minimize such assumptions.

Copy link
Contributor Author

@FUDCo FUDCo Apr 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So are we going to explicitly allow symbol-named methods here and leave it to Far to reject them?
What about symbol-named facets?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thinking about this further, symbol-named facets aren't straightforward, because I need to put them in order and sorting Symbols is a pain. In any event, I don't think there's a use case for this aside from obsessive generality, so let's take the idea of symbol-named facets off the table for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On deeper analysis, symbol-named methods are kind of PITA too, though if we think it's worth the effort I can do it. But I really don't think it's worth the effort.

Copy link
Member

@erights erights Apr 3, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Definitely no symbol-named facets. The record naming facets is a copyRecord, and the properties of a copyRecord must be string-named own enumerable properties, so they're exempt from all these painful differences between ways to enumerate own properties. So this restriction is architectural, not expedient.

symbol-named methods here and leave it to Far to reject them?

Far does not reject symbol-named methods. Nor does it reject methods named by non-enumerable properties.

But we currently have only one case we need, @@asyncIterator, which we could continue to special case for now. If postponing general support for symbol-named methods gets us to MN1 faster, I'm all for postponing. But I think our distributed computational model should eventually support symbol-named methods in general.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I can put in symbol-named methods in less than, say, an hour's work I'll do it. I suspect I probably can.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A weird thought occurred to me as I was pondering implementation: as long as we do not support symbol-named methods in our over-the-wire message encoding, someone can use symbol-named methods as a kind of private-to-the-local-vat scoping technique. I'm not saying this is a good idea, but I can imagine people doing it. Then, when we turn that feature on, we break their imagined security perimeter. (Even once we support symbols in the method selector portion of a message, I presume they would still be able to use non-registered, non-well-known symbols for this purpose.) This makes me wonder if we should hold off implementing symbol-named methods until we are also implementing symbols as method selectors in messages.

@FUDCo
Copy link
Contributor Author

FUDCo commented Apr 4, 2022

I think this is now ready for final review.

Note to @michaelfig @Chris-Hibbert @turadg: would you please take a look at packages/run-protocol/src/vaultFactory/vault.js? I had to make fairly invasive changes to update it for the new defineKind API,, which I don't believe changed any of the semantics (it passes all the tests, anyway), but given the radical transformation I prefer somebody take a look who actually understands the substance of the underlying code.

@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from 586ac9b to 4dad8be Compare April 5, 2022 00:09
@turadg
Copy link
Member

turadg commented Apr 5, 2022

would you please take a look at packages/run-protocol/src/vaultFactory/vault.js

Thanks for the ping. I don't see any change in semantics, which is good. I see a separation of selfBehavior and helperBehavior, which is good. I do have some concerns.

  1. Git blame churn. Many lines in this file are being touched. I suggest we have a codeowner of run-protocol be the author of the commit for vault.js so that git blame tracks back. I'm happy to take that on.

  2. Loss of JSDoc. JSDoc (at least in my IDE) is on the value of the object and when a function is composed into a new object (e.g. selfBehavior) it doesn't come along. I think each self behavior function should be nested in the selfBehavior object. Without that the function documentation will be lost in the calling context.

  3. Untyped facets. That can be fixed with,

/**
 * @typedef {{
 *   state: ImmutableState & MutableState,
 *   facets: {
 *     self: import('@agoric/vat-data/src/types').FunctionsMinusContext<typeof selfBehavior>,
 *     helper: import('@agoric/vat-data/src/types').FunctionsMinusContext<typeof helperBehavior>,
 *   },
 * }} MethodContext
 */
  1. Loss of argument names in types. With the type transformation to remove the first parameter, the names of the other parameters become args_0 etc. I don't know what to do about this. Maybe there's a trick to do in FunctionsMinusContext. I'll research this.

  2. Loss of type information within behavior functions. Previously the type of state was declared once and shared in each behavior function because the value was shared. Now the context passed in can be anything unless there's an annotation constraining it. I don't know how to solve this without annotating each function.

  3. Loss of calback types like OfferHandler. This could be solved with a PlusContext partner for MinusContext. E.g. {WithContext<OfferHandler>} below.

    /* * @type {OfferHandler} XXX needs a proper type def; this one won't do */

Not all the above has to be solved in this PR. My blocking requests are to:

  • inline the function definitions to the behavior objects
  • type facets in MethodContext

packages/ERTP/src/payment.js Outdated Show resolved Hide resolved
const collateralBrand = manager.getCollateralBrand();
const debtBrand = manager.getDebtBrand();
// #region Computed constants
const collateralBrand = ({ state }) => state.manager.getCollateralBrand();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please move the behavior functions within the object that will hold them

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm unclear what you mean by "the behavior functions". Did you mean inline all the behavior functions or just the two that you highlighted in this comment? Because they weren't all inlined before, by any means.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I did mean all of them. They weren't all inlined in object creation but they were all nested and that's a property that I want to maintain. They also all had JSDoc before and the new object construction breaks that unless they're inlined.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Please give it a look.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perfect, thank you.

Copy link
Member

@warner warner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two small changes to make, plus the xsnap-native submodule change needs to not be in this PR. Rebasing onto trunk might clear that out, but if not grab me and we can figure it out.

packages/SwingSet/src/liveslots/virtualObjectManager.js Outdated Show resolved Hide resolved
unweakable.add(state);
if (facetNames === null) {
const context = { state };
unweakable.add(context);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because I just wondered about it again, and it took me a minute to convince myself it was ok, let's add a one-line comment here

# 'context' does not need a linkToCohort because it's held by the bound methods

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, crud, I got the comment backwards, and it's going to confuse me in its current state

please replace with:

'context' does not need a linkToCohort because it holds the facets (which hold the cohort)

sorry

@FUDCo
Copy link
Contributor Author

FUDCo commented Apr 5, 2022

How do I expunge the xsnap-native nonsense that somehow got sucked into this PR? Rebasing didn't seem to do the trick.

@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from 4dad8be to 5065fa9 Compare April 5, 2022 20:40
@FUDCo FUDCo requested a review from warner April 5, 2022 20:43
@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from c6d08ff to 6b728a3 Compare April 6, 2022 01:04
Copy link
Member

@warner warner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

r+ module that one extra comment change

unweakable.add(state);
if (facetNames === null) {
const context = { state };
unweakable.add(context);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh, crud, I got the comment backwards, and it's going to confuse me in its current state

please replace with:

'context' does not need a linkToCohort because it holds the facets (which hold the cohort)

sorry

@FUDCo
Copy link
Contributor Author

FUDCo commented Apr 6, 2022

r+ module that one extra comment change

OK, but I think your prior attempt at the comment was also correct.

@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from 6b728a3 to 1d3d756 Compare April 6, 2022 04:35
@FUDCo FUDCo requested a review from turadg April 6, 2022 04:35
@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from 1d3d756 to 43df7ec Compare April 6, 2022 18:07
@FUDCo FUDCo added automerge:rebase Automatically rebase updates, then merge and removed automerge:rebase Automatically rebase updates, then merge labels Apr 6, 2022
@FUDCo FUDCo force-pushed the 4905-revised-revised-kind-api branch from 43df7ec to 3e02d42 Compare April 6, 2022 18:09
@FUDCo FUDCo added the automerge:rebase Automatically rebase updates, then merge label Apr 6, 2022
@mergify mergify bot merged commit fd61223 into master Apr 6, 2022
@mergify mergify bot deleted the 4905-revised-revised-kind-api branch April 6, 2022 18:24
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
automerge:rebase Automatically rebase updates, then merge enhancement New feature or request SwingSet package: SwingSet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

new defineKind API with { state, facets } argument
6 participants