Skip to content

Abstract Syntax

Kris Kowal edited this page Sep 10, 2024 · 33 revisions

This document captures a summary of consensus and remaining contention for the OCapN data model and abstract syntax, excluding the concern of concrete representation of these on the wire, but including representation and semantics in implementation languages.

Agoric currently requires all valid JSON documents to be passable over OCapN, so type titles suffixed "(JSON)" participate in this language subset. This itself remains a contended position.

Atoms

Undefined

  • Guile: *unspecified*
  • JavaScript: undefined
  • Python: None

Null (JSON)

In order for the JSON subset of JavaScript to be passable, Undefined must be distinguishable from Null. For this purpose and this purpose alone, we preserve this second empty (or "unit") type. Consequently, a JavaScript program can parse a JSON file, bounce it off a remote Guile program, and write equivalent JSON back with the host implementation of JSON.parse and JSON.stringify. We presume that a JSON codec implemented in Guile can be implemented to parse and format the same subset of the OCapN data model.

  • Guile: tentatively json-null (imported)
  • JavaScript and JSON: null
  • Python: Null (imported)

@erights inisists on the JSON null https://github.com/ocapn/ocapn/issues/5#issuecomment-826029525

Boolean (JSON)

  • Guile: #f, #t
  • JavaScript and JSON: false, true
  • Python: False, True

Integer

OCapN supports arbitrary precision signed integers.

  • Guile: -1, 0, 1
  • JavaScript: -1n, 0n, 1n
  • Python: -1, 0, 1

We achieved consensus on the name Integer at the November 14, 2023 meeting.

Float64 (JSON)

OCapN round trips all double precision floating point numbers as expressible with IEEE 754, except that OCapN considers all IEEE 754 NaNs as equivalent, i.e., as jointly representing a single abstract NaN value. Thus, any concrete NaN representation may validly round trip even if it results in a different concrete representation. However, we encourage concrete representations to use a canonical NaN representation.

Concretely, the canonical NaN is 0x7ff8_0000_0000_0000, though this is not a concern of the abstract syntax and data model.

OCapN preserves the distinction between +0 and -0.

Language Negative Positive
Guile -0.0 0.0
JavaScript -0 0
Python -0.0 0.0

OCapN round trips positive and negative infinity.

Language Negative Positive
Guile -inf.0 +inf.0
JavaScript -Infinity Infinity
Python float('-inf') float('inf')

OCapN collapses all versions of NaN to a single abstract NaN.

  • JavaScript: NaN
  • Guile: +nan.0
  • Python: float('nan')

OCapN provides no support for other floating point precisions.

All real and finite double precision floating point numbers participate in the JSON subset of OCapN. We expect OCapN-compatible JSON codecs, including the JavaScript JSON codec, to round-trip all numbers except NaNs, infinities, and negative zero, but all other numbers expressible with an IEEE 754 double-precision float to survive a round trip without loss of precision. We also do not expect integers expressed with higher precision in JSON to survive a round-trip through an OCapN-compatible JSON codec.

Consensus on preserving -0:

Tracking: https://github.com/ocapn/ocapn/issues/58

String (JSON)

OCapN supports strings of unicode code points.

  • Guile: ""
  • JavaScript: ''
  • Python: ''

There remains contention whether OCapN can round trip unpaired surrogates. If OCapN's data model must be a strict superset of JSON, OCapN must be able to round trip unpaired surrogates, which are not expressible in UTF-8. https://github.com/ocapn/ocapn/issues/5#issuecomment-826029525 (per @erights).

Strings participate in the JSON superset.

Contended positions:

Tracking: https://github.com/ocapn/ocapn/issues/47

Jan 2024 meeting notes record that we agreed that strings can only be well-formed Unicode, i.e., cannot contain unpaired surrogates. For JavaScript, if a string does not pass the isWellFormed predicate, then it is not a Passable string. Agoric has yet to implement this validation, but will.

ByteArray

OCapN supports arbitrary length byte strings.

  • Guile: #vu8()
  • JavaScript: To be determined, but likely an object with Symbol.for('passStyle') set to bytes and an API for moving the bytes into a mutable buffer or composing with other immutable byte strings.
  • Python: b''

Tracking: https://github.com/ocapn/ocapn/issues/48 Contention: TBD (byte, octet) x (vector, array, string)

At the November 14, 2023 meeting, we agreed to settle on the prefix “byte” and agreed to decide at the next meeting based on a reactji poll.

Jan 2024 meeting notes record that we agreed on ByteArray because it was the winner of the poll, and we had already agreed to resolve this specific issue by poll among these three choices.

Selector

  • Guile: symbol 'name
  • JavaScript:
    {
      [Symbol.for('passStyle')]: 'selector',
      selector: 'name'
    }`
    or makeSelector('name') where makeSelector is imported from ocapn.
  • Python: Selector('name') where Selector is imported from ocapn.

Tracking: https://github.com/ocapn/ocapn/issues/46

Container

List (JSON)

OCapN supports arbitrary length lists of other passable values.

  • Guile: '()
  • JavaScript and JSON: []
  • Python: () (We have not discussed whether to use tuple or list. Tuple is less mutable, though enforcing immutability in Python is not likely to be a goal the way it is in hardened JavaScript.)

Sequences participate in the JSON superset.

We achieved consensus to name the type “List” at the November 14, 2023 meeting.

Struct (JSON)

A struct is a dictionary with unique, unordered string keys and passable values.

For the purposes of surviving a round trip, the order of appearance of entries in the struct must not be important for determining equivalence.

Thus, a Struct representation concretely using one key order may validly round-trip into a Struct representation using another key order. However, we encourage concrete representations to use some canonical key order, though this is not a concern of the abstract syntax and data model.

  • Guile: make-tbd-hash a hash of undecided type
  • JavaScript: {}
  • Python: {}

There are no contended positions.

Non-contended positions held:

Tagged

OCapN supports user-extensible tagged values, consisting of a String tagName and a Passable payload.

  • Guile: currently a Guile record labeled '(syrec ...) (imported)
  • JavaScript: an object with the key Symbol.for('passStyle') and value tagged, with a string tagName and a single "payload" field carrying the tagged value.
    { 
      [Symbol.for('passStyle')]: 'tagged', 
      [Symbol.toStringTag]: tagName,
      payload
    }
  • Python:

Consensus positions:

Contended positions:

  • Spritely seems to use symbols as tagNames rather than strings.

Tracking:

Remotable

A Remotable can be

  • An object that can receive remote messages
  • A remote presence of such an object, that forwards messages to that object

This taxonomy does not distinguish between these two forms of Remotable, since this taxonomy is intended to be pass-invariant.

  • Guile:
  • JavaScript: A far object or a remote presence of that far object.
    { 
      __proto__: {
        [Symbol.for('passStyle')]: 'remotable', 
        [Symbol.toStringTag]: allegedInterfaceName,
      },
      ...methods
    }
  • Python:

Remotables and Promises are both capabilities for delivering messages to possibly remote objects. Unlike Promises, Remotables have a fresh, stable unforgeable, pass-invariant, comparable identity.

Tracking: https://github.com/ocapn/ocapn/issues/49

Promise

  • Guile:
  • JavaScript: a JavaScript promise
  • Python:

Contention:

  • fulfills to a single value
  • fulfills to multiple values
  • hand-off records appear in-band in Goblins, whereas Agoric uses promises

Tracking https://github.com/ocapn/ocapn/issues/55

Error

OCapN can transit errors. We have not yet converged on any particular details about the modeling of errors. The purpose of errors is typically to indicate that some requested operation failed. The purpose of the contents of errors is to preserve and convey diagnostic information, mostly to help debug problems, such as the root cause of a surprising failure. This is a best-efforts obligation, for which we have not yet decided either what contents are required, nor what is allowed, nor what must be preserved as errors are passed from one site to another. Until these details are decided, the only hard requirement is that an error round trip to an error. We avoid any interpretation for now as to whether it is the "same" error.

  • Guile:
  • JavaScript: a JavaScript Error object
  • Python:

This concludes the taxonomy and abstract syntax of the core data model. From here down is the abstract syntax of capability-based message passing, which is built on top of this core data model.


Messages

Deliver

Contended positions:

  • @zenhack one argument, one return https://github.com/ocapn/ocapn/issues/16
  • @kriskowal normalize method name, effectively a list of ASCII lowercase alphanumeric terms starting with an alphabetic character that get reified and recognized in each implementation language's rustic aesthetic, be it strings or symbols in whatever case convention most closely resembles the prevailing trend.

Tracking: https://github.com/ocapn/ocapn/issues/54 Tracking: https://github.com/ocapn/ocapn/issues/65

Conventions

Bootstrap

Tracking: https://github.com/ocapn/ocapn/issues/62

Locator

Order

Clone this wiki locally