-
Notifications
You must be signed in to change notification settings - Fork 212
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
using representatives in stores during init() #1938
Comments
So the current #455 "virtual objects" API we're landing (in #1907) will let users write code like this: const paymentLedger = makeWeakStore(); // value: balance
function representPurse(state) {
const purse = {
initialize(initialBalance = 0) {
state.balance = initialBalance;
state.deposit = makeDeposit(purse);
},
deposit(srcPayment) {
const srcPaymentBalance = paymentLedger.get(srcPayment);
paymentLedger.delete(srcPayment);
state.balance += srcPaymentBalance;
return srcPaymentBalance;
},
// ... other methods
};
return purse;
}
const makePurse = makeKind(representPurse);
function representPayment() {
const payment = {
initialize(amount) {
paymentLedger.init(payment, amount);
},
getAllegedBrand: () => brand,
};
return payment;
}
const makePayment = makeKind(representPayment); In Payment's This only works if the weak-store code (embedded in But in the current PR, it doesn't add the entry to The shallow fix is for This example is pretty contrived, but I think it demonstrates the problem: const ledger = makeWeakStore();
const other = {
subscribeMe(them) {
ledger.get(them).getAmount2();
},
};
function representFoo(state) {
const foo = {
initialize(amount1, amount2) {
ledger.init(foo, amount1);
state.amount2 = amount2;
other.subscribeMe(foo);
},
getAmount2() {
return state.amount2;
},
};
return harden(foo);
}
const fooMaker = makeKind(representFoo); For Worse, this pattern looks like it should work, because if If we were strictly using the rights-amplification pattern everywhere (even for const fooLedgerAmount1 = makeWeakStore();
const fooLedgerAmount2 = makeWeakStore();
function representFoo() {
const foo = {
initialize(amount1, amount2) {
fooLedger1.init(foo, amount1);
fooLedger2.init(foo, amount2);
other.subscribeMe(foo);
}, and I think adding |
If we enter the new virtual object in the The reason there appears to be a problem in your example is because you are using |
Oops. Ok, here's a different example.. still a bit contrived, but I think we could imagine our developers writing something like this and expecting it to work. const bidNotifiers = makeWeakStore();
function representAucion(state) {
const auction = {
initialize() {
state.currentBest = null;
state.bids = [];
},
addBid(bid) {
// state.bids.push(bid); // would this even work? doesn't trigger setter
const bids = state.bids;
bids.push(bid);
state.bids = bids; // ugh
auction.sort();
},
removeBid(bid) {
const bids = state.bids;
for (let i=0; i++; i < bids.length) {
if (sameKey(bids[i], bid)) {
bids.splice(i, 1);
}
state.bids = bids;
}
},
sort() {
const bids = state.bids;
const amountsIndex = bids.map((bid, index) => [bid.getAmount(), index]);
amountsIndex.sort((a,b) => b[0] - a[0]);
state.bids = amountsIndex.map((bid, index) => bid);
},
results() {
const bids = state.bids;
const losers = bids.slice(0, bids.length-1);
let winner;
if (bids.length) {
winner = bids[bids.length-1];
}
return { winner, losers };
},
close() {
const { winner, losers } = auction.results();
if (winner) {
const notifier = bidNotifiers.get(winner);
E(notifier).youWon();
}
losers.map(loser => E(bidNotifiers.get(loser)).youLost());
},
};
return auction;
}
function representBid(state) {
const bid = {
initialize(auction, amount, notifier) {
bidNotifiers.set(bid, notifier);
state.amount = amount;
auction.addBid(bid);
},
};
return bid;
}
const auctionMaker = makeKind(representAucion);
const bidMaker = makeKind(representBid);
const auction = auctionMaker();
const newBid = bidMaker(auction, 20, notifier); (the funny dance in In this example, I think calling
Looking at the current #1907 PR (848eda7), I think the stack will look like:
This is super-thorny. I don't have a good suggestion on fixing it yet, other than to think about how we could simplify things (which is probably in conflict with providing an ergonomic API). My one observation is that relying upon |
Ooh, @FUDCo and I just thought of a fix: add away to pin |
This might have been fixed as a side-effect of our big #4905 virtual-kind API change. |
Yes. Closing. |
I think we need to do
valToSlotTable.set(tempInstance, instanceKey)
before callingtempInstance.init
. The user-suppliedinit
function is likely to interact with other representatives and WeakStores, and it might pass itself to one of those for use as a key: imagine the Purse/Payment/DepositFacet, and a case where the deposit facet does adepositLedger.init(deposit, purse)
during initialization. We need to get ourinstanceKey
associated with this instance early enough to allow those calls to work.It's not trivial, though, because those same calls might also read from a WeakStore, and we won't be prepared to build a new Representative until we've saved the data from
init
. I think we can land this before solving the problem, but we absolutely must build a unit test that exercises it so we know what more needs to be done.So, actually let's put a comment here reminding us to add that
valToSlot
addition, but let's not implement it yet, because I think doing it halfway might mask the kind of bug I'm anticipating.Originally posted by @warner in #1907 (comment)
The text was updated successfully, but these errors were encountered: