SharedStructs are to be declarations, like class declarations, that may appear in module source text.
Instances of a shared struct are JavaScript primitives and, like all other JavaScript primitives, share a per-Realm prototype instance.
So, like 1..toString()
looks up the %NumberPrototype%
intrinsic for the realm in the current execution context in order to call its toString
method,
when we have a struct instance s
, calling s.toString()
will look up the struct’s corresponding prototype on the realm in the current execution context.
The key space for that table closes over the key space of the realm’s module map and also includes the position of the struct declaration.
Consequently, shared struct declarations must instantiate all contained prototypes once per evaluation of a module in the realm’s module map.
I am comfortable with this strategy in anticipation of a suitable intersection semantics for Module Harmony proposals Virtual Modules, Evaluators, and Compartments. For all of these cases, we would throughout 262, introduce a level of indirection between the current execution context and realm that I tentatively call a “Cohort”. A cohort contains a module memo and a shared struct memo and otherwise refers to a particular realm, such that multiple cohorts can share a realm. We would presumably designate an alternative cohort with an “evaluators” instance, so that a Module instance could choose which cohort of shared structs it will consult when it is evaluated.
I expect shared structs to compose in this fashion:
const source = new ModuleSource(`
export shared struct Point2d { x; y }
`);
const m1 = new Module(source);
const m2 = new Module(source);
const { Point2d: alfa } = await import(m1);
const { Point2d: bravo } = await import(m2);
// because m1 and m2 are of the same realm and cohort
alfa === bravo;
alfa.prototype === bravo.prototype;
// m3 and m4 will belong to a distinct cohort.
const evaluators = new Evaluators();
const m3 = new evaluators.Module(source);
const m4 = new evaluators.Module(source);
const { Point2: charlie } = await import(m3);
const { Point2: delta } = await import(m4);
// consequently, they share the same per-cohort constructor and prototype
charlie === delta;
// but do not share with the primary realm
charlie !== alfa;
The significance of this resolution and why it is necessary to make progress on shared structs is that shared struct prototypes are and should be born mutable by default, but it must be possible through evaluators or compartments to partition a realm such that a host/guest arrangement can be made, where the guest cannot interfere with the host by altering shared struct prototypes it holds closely. Because these prototypes are addressed by syntax and the execution context, it must be possible to deny the guest access to the host’s prototypes through a different execution context.
Credit for this resolution belongs to Nicolò and if this misrepresents their position, the error is mine.