Good point. I probably should have cut to the chase and sent my response as a PR. I'll do that as soon as I'm back at a non-phone keyboard.
On Wed, Jul 19, 2017, 3:56 PM Daniel Sank <[email protected]> wrote: > Allow me to state the obvious: whatever comes out of this discussion > should probably result in an update of the spec file. Searching mailing > list history is great but... oh wait never mind searching mailing list > history is terrible :-) > > On Wed, Jul 19, 2017 at 2:57 PM, Ross Light <[email protected]> wrote: > >> Replies inline (with the disclaimer that I'm not Kenton, my only >> credentials are that I have stared at this file for a long time): >> >> On Wed, Jul 19, 2017 at 1:46 PM Thomas Leonard <[email protected]> wrote: >> >>> Hi, >>> >>> I'm trying to write an implementation of the RPC spec (level 1, in >>> OCaml). I found a few parts of the spec unclear - could someone clarify >>> them for me? >>> >>> It says: >>> >>> [ExportId] >>> > The exporter chooses an ID before sending a capability over the wire. >>> If >>> > the capability is already in the table, the exporter should reuse the >>> same ID. >>> >>> But later: >>> >>> [CapDescriptor] >>> > senderHosted @1 :ExportId; >>> > A capability newly exported by the sender. This is the ID of the new >>> capability in the >>> > sender's export table (receiver's import table). >>> >>> How can the exporter reuse the same ID, if it has to be newly exported? >>> >> >> That seems like a doc/spec typo. You can always specify an existing >> capability. I think the wording should be something like: "A capability >> exported by the sender. This may or may not be a new ID in the sender's >> export table (receiver's import table)." >> >> >>> [Message] >>> > This could be e.g. because the sender received an invalid or >>> nonsensical >>> > message (`isCallersFault` is true) or because the sender had an >>> internal error >>> > (`isCallersFault` is false). >>> >>> isCallersFault appears to be deprecated (`obsoleteIsCallersFault` >>> appears much later). >>> >> >> Yup, Exception has changed (IMO for the better). Instead of placing >> blame on sender or receiver (such distinctions are hard to draw in >> general), exceptions are now about what action that caller is advised to >> take based on the failure. >> >> [Call.sendResultsTo] >>> > When `yourself` is used, the receiver must still send a `Return` for >>> the call, but sets the >>> > field `resultsSentElsewhere` in that `Return` rather than including >>> the results. >>> >>> When should `resultsSentElsewhere` be returned? Once the result is >>> known? Or >>> once the first takeFromOtherQuestion collects it? >>> >> >> (I haven't implemented this for Go yet, but want to.) AFAICT >> resultsSentElsewhere should be sent once the result is known. >> >> >>> Can takeFromOtherQuestion be used more than once for a single source >>> question? >>> >> >> I would assume that it could be used until Finish message is sent for >> that question, much like other question-based data. In practice, every >> call's result is held in the answers table until Finish is received. >> >> >>> > The `Call` for bar'() has `sendResultsTo` set to `yourself`, with the >>> value being the >>> > question ID originally assigned to the bar() call. >>> >>> What does "the value" refer to here? `yourself` has type `Void`. >>> >> >>> > Vat B receives the `Return` for bar'() and sends a `Return` for bar(), >>> with >>> > `receivedFromYourself` set in place of the results. >>> >>> `receivedFromYourself` does not appear anywhere else in the spec. >>> >> >> I think this whole example is stale and probably needs another draft. >> >> >>> [Return.releaseParamCaps] >>> > If true, all capabilities that were in the params should be considered >>> released. >>> >>> Just to be sure: as if the sender had sent a release message for each >>> one with `count=1`? >>> >> >> (I might be wrong on this point, it's been a while since I've looked. >> The docs should probably spell this out.) Usually. The list of >> CapDescriptors in a Payload could point to the same capability multiple >> times. A release message of count=1 per CapDescriptor is a more accurate >> way of phrasing this. >> >> >>> [Payload] >>> Why is it not possible to send exceptions in payloads? Should I export >>> each >>> broken capability as an export and then immediately send a Resolve for >>> each >>> one, resolving it to an exception? >>> >> >> Payload is only used for parameters and results. It doesn't make sense >> for parameters to be an exception, and results is inside a union where you >> could specify an exception that is an alternative. I'm not sure I >> understand the use-case where you are sending a broken capability. >> >> >>> [Resolve] >>> > When an export ID sent over the wire (e.g. in a `CapDescriptor`) is >>> indicated to be a promise, >>> > this indicates that the sender will follow up at some point with a >>> `Resolve` message. If the >>> > same `promiseId` is sent again before `Resolve`, still only one >>> `Resolve` is sent. If the >>> > same ID is sent again later _after_ a `Resolve`, it can only be >>> because the export's >>> > reference count hit zero in the meantime and the ID was re-assigned to >>> a new export, therefore >>> > this later promise does _not_ correspond to the earlier `Resolve`. >>> >>> It's not clear to me why it is useful for the receiver to know this. >>> Presumably the sender can't reuse an export ID until the receiver >>> explicitly releases it anyway. >>> Should an implementation keep track of whether a resolve has arrived yet >>> and behave differently based on this when it sees an export ID? >>> >> >> It's more specifying that the receiver should not resolve the promise >> more than once. I believe in this case that it would be a protocol >> violation, in which case the correct behavior would be for the receiver to >> send an abort. >> >> > The sender promises that from this point forth, until `promiseId` is >>> released, it shall >>> > simply forward all messages to the capability designated by `cap`. >>> >>> Does something similar apply to Return messages? Might be worth >>> mentioning it there too. >>> >> >> I believe so, but I don't know/remember. :( >> >> >>> [Disembargo] >>> > Embargos are used to enforce E-order in the presence of promise >>> resolution. That is, if an >>> > application makes two calls foo() and bar() on the same capability >>> reference, in that order, >>> > the calls should be delivered in the order in which they were made. >>> But if foo() is called >>> > on a promise, and that promise happens to resolve before bar() is >>> called, then the two calls >>> > may travel different paths over the network, and thus could arrive in >>> the wrong order. In >>> > this case, the call to `bar()` must be embargoed, and a `Disembargo` >>> message must be sent along >>> > the same path as `foo()` to ensure that the `Disembargo` arrives after >>> `foo()`. >>> >>> What does "this case" refer to? When exactly is an embargo needed, and >>> when not? >>> >> >> If you're implementing level 1 (two-party), then really the only place >> where this applies is when you receive a capability that the receiver hosts >> as part of a return or resolve after you have made calls on the promised >> capability. This implies that the RPC system needs to keep track of which >> parts of the answer have had calls made on them. When this occurs, the >> receiver gives the application code an embargoed client, and then sends a >> Disembargo with senderLoopback set. It releases the embargo once the same >> disembargo ID is returned with receiverLoopback set. >> >> For me, this was the hardest part of the spec to understand. I >> understand why it's needed, but it's really hard to grok the implications. >> >> > There are two particular cases where embargos are important. Consider >>> object Alice, in Vat A, >>> > who holds a promise P, pointing towards Vat B, that eventually >>> resolves to Carol. >>> >>> Could Carol be another promise here? Should Alice wait until the target >>> is fully resolved before doing a disembargo, or do a disembargo for each >>> step? >>> >> >> See above explanation. But no, Carol cannot be a promise, since the only >> time that an embargo is triggered is once you get back a locally hosted >> capability. >> >> >>> [Accept] >>> > This message is also used to pick up a redirected return -- see >>> `Return.redirect`. >>> >>> `redirect` doesn't appear anyway else in this spec. I guess it's >>> `Return.sendResultsTo.thirdParty`. >>> >> >> Probably. It's Level 3, so it's invisible to me. :D >> >> >>> >>> [ Network-specific Parameters] >>> > For interaction over the global internet between parties with no other >>> prior arrangement, a >>> > particular set of bindings for these types is defined elsewhere. >>> (TODO(someday): Specify where >>> > these common definitions live.) >>> >>> Do these definitions exist now? >>> >> >> ¯\_(ツ)_/¯ >> >> >>> >>> Thanks! >>> >>> -- >>> You received this message because you are subscribed to the Google >>> Groups "Cap'n Proto" group. >>> To unsubscribe from this group and stop receiving emails from it, send >>> an email to [email protected]. >>> Visit this group at https://groups.google.com/group/capnproto. >>> >> -- >> You received this message because you are subscribed to the Google Groups >> "Cap'n Proto" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to [email protected]. >> Visit this group at https://groups.google.com/group/capnproto. >> > > > > -- > Daniel Sank > > > -- You received this message because you are subscribed to the Google Groups "Cap'n Proto" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. Visit this group at https://groups.google.com/group/capnproto.
