16:02
<littledan>
hi all
16:02
<Kris Kowal>
I’m in the lobby https://meet.google.com/row-whjm-rpn
16:02
<Jack Works>
+1
16:02
<Kris Kowal>
Not sure whether this is the venue, shu
16:02
<littledan>
me too, waiting to get in
16:02
<naugtur>
I'm in there too
16:03
<littledan>
Kris, excellent slides
16:03
<Mathieu Hofman>
I'm still waiting to be let in
16:03
<Kris Kowal>
Great, fi was shooting for “bad”
16:03
<shu>
sorry, previous meeting ran over, omw
16:09
<Luca Casonato>
If you are in the waiting room, maybe try rejoin?
17:25
<shu>
yulia: still around?
17:26
<shu>
can you join the meet again rq? i can't add a co-host via the calendar configuration dialogs for some reason, i wonder if i need to do it within the call itself
17:26
<yulia>
yes
17:27
<shu>
okay, i'm off the call now, see if you can rejoin without me being there
17:27
<yulia>
it forces me to request again
17:27
<yulia>
so i can't enter without you
17:27
<shu>
hmm
17:28
<nicolo-ribaudo>
If I remember correctly, people invited to the calendar event can join without permission. It's not ideal, but we can start by inviting all the people that were present today
17:29
<littledan>
leo reported being able to join without waiting in the lobby
17:29
<nicolo-ribaudo>
Leo was one of the people invited on calendar
17:30
<yulia>
uhhhh
17:30
<yulia>
it still doesnt work
17:30
<shu>
oops, forgot to save
17:30
<shu>
sorry try again
17:30
<yulia>
ahaha
17:30
<yulia>
\o/ it works
17:30
<shu>
okay great, it should also let you admit other people next time
17:30
<shu>
thanks for testing
17:32
<shu>
for next time: Yulia, Kris, Dan, and Jack Works are co-hosts and can admit other folks
17:33
<shu>
also, just realized, next meeting falls on US 4th of July holiday
17:33
<shu>
any conflicts for same time on Wed, Jul 6?
17:34
<nicolo-ribaudo>
There is the SES meeting that starts one hour after te modules one, it might be a problem if we do 1:30h
17:35
<shu>
i see that, yes, though given all the SES folks are here and this is also top-of-mind for them, perhaps it'd be fine
17:36
<guybedford>
You mean 5th of July right?
17:36
<shu>
i mean 6th of July
17:36
<shu>
4th and 5th are both holidays
17:37
<shu>
at least it is at Google
17:37
<guybedford>
ah gotcha, consolidating may well be an option for that one then
17:37
<shu>
if it's just me i can just skip the next call, Yulia is running it anyhow
17:37
<yulia>
sure
17:40
<guybedford>
Your call - not sure how many people won't be able to make the 5th? I can do either day.
17:45
<shu>
i'd like to not create any pressure for US-based folks so i'd prefer moving it to the 6th
17:49
<Kris Kowal>
There is the SES meeting that starts one hour after te modules one, it might be a problem if we do 1:30h
We’ll deconvene the SES meeting if a Compartments meeting overlaps.
17:49
<Kris Kowal>
That is actually our preference.
17:51
<Kris Kowal>
Speaking of which, we’d previously built a SES meeting agenda tomorrow for guybedford to join us and hash out what a VirtualStaticModuleRecord for WASM would concretely look like. The artifact would be an example PR for the Compartment proposal. I’m inclined to keep that on the docket and use the PR to sync with this interest group, if there are no objections.
18:58
<Kris Kowal>
Daniel Ehrenberg: Regarding carrying import.meta and the referrer specifier for a module to another compartment and the importance or non-importance of the identity of a module block https://docs.google.com/document/d/1CD5lIBZLl24XBWbQhokqBdt4Zl7wPAcFJKJrgePr9HU/edit#bookmark=id.o21po234q3z
18:59
<Kris Kowal>
If a module block is reified as a “module descriptor” ~ {record, specifier, importMeta}, the identity of the object still doesn’t matter. The specifier matters because that is the key in the module memo.
19:00
<Kris Kowal>
That is to say, a map of module descriptors could be transported to another worker without losing any of the relationships between modules.
21:04
<littledan>
about layering, I want to push back on the idea that was raised in the meeting today about all proposals depending on compartments or some reduction of it. I'd prefer that we focus on figuring out what the big picture API is, and then it will be more clear which pieces we can ship; I think there are lots of orderings that would work, and we shouldn't focus too excessively on working out one factoring or another. For example, I think it'd be OK to ship module reflection or module blocks before we have an imperative API to provide the way that modules link to each other.
21:09
<shu>
+1
21:09
<shu>
that is the conclusion i personally would be happier with and we should give it a full discussion next call
21:10
<shu>
i wanted to explicitly surface the question which i felt was implicit in Kris's presentation
21:12
<littledan>
I really liked Kris's presentation. It brought together a bunch of ideas really well. I think it's important that we maintain a unified model for how modules work, and the compartments proposal stands out as it exposes so much
21:14
<shu>
also agree
21:55
<Kris Kowal>
To be clear, I also consider the question of ordering and layering open and I don’t have a preference toward shipping compartments first. I just do not, from where I’m sitting right now, see a way to do that in a way that doesn’t hobble the proposal that lands first.
21:57
<Kris Kowal>
For example, suppose we land module blocks first. There needs to exist some mechanism for instantiating the block. For deferred execution, same issue. Import reflection could be exposed, but none of the motivating use cases work without a loader.
21:58
<Kris Kowal>
ShadowRealm may give us a degree of freedom in that regard.
22:00
<Kris Kowal>
To the extent that ShadowRealm encapsulates a loader. But even then, the result differs in name only from the part we later factor out of realm. So, big +1 to littledan’s point about getting a holistic view before figuring out layering.
22:04
<Kris Kowal>
Also, ShadowRealm and workers of every kind should probably be born with host-defined loader hooks, since serializing a loadHook fraught in the former and dubious in the latter. But in combination with a compartment, having a realm bootstrap off of the host-defined loader and constructing a Compartment with a user-defined loader opens up options.
22:17
<littledan>
the main mechanism for instantiating module blocks is import()
22:17
<littledan>
the proposal stands on its own without further control, IMO
22:18
<littledan>
I agree that ShadowRealm should probably take a LoaderOptions bag as an argument
22:18
<littledan>
but, also there, ShadowRealm is useful without that
22:18
<Kris Kowal>
So, assuming that, then Compartments would have import and loadHook competing to register module descriptors.
22:18
<littledan>
huh?
22:19
<littledan>
I meant the already-existing dynamic import()
22:19
<littledan>
as well as passing the module block to structured clone
22:19
<Kris Kowal>
Understood. I propose that a desirable invariant is for dynamic import and compartment import be nearly the same.
22:19
<littledan>
I agree that we shouldn't have competing hooks. Surma and I proposed module block without hooks.
22:19
<littledan>
yes, definitely they should be the same
22:20
<littledan>
so, sure, you can pass a module block to compartment import once there are compartments
22:20
<Kris Kowal>
Consider: import(module { import 'x.js'; })
22:21
<Kris Kowal>
Followed by (approximately) import({ specifier: 'x.js', ...module { } })
22:21
<Kris Kowal>
And let’s assume that module blocks correspond to module descriptors.
22:22
<Kris Kowal>
The behavior of this example is order dependent (even without the introduction of compartment).
22:22
<Kris Kowal>
Because there already is a host loader in play.
22:22
<Kris Kowal>
In the former case, you push a module into the module map, but in order for its dependencies to be satisfied, the loader must pull them in.
22:23
<Kris Kowal>
So you’d have to take care to push your dependencies into the loader from leaf to root. Which is fine, but fragile.
22:23
<Kris Kowal>
I contend that it’s fragile enough that it is inadvisable.
22:25
<Kris Kowal>
When compartments get reified, then there’s a missed opportunity for the compartment to represent a capability to induce a module to be loaded, not to determine what is loaded.
22:26
<Kris Kowal>
That is to say, a loadHook provides a coherent top-down view of how to construct a coherent module graph. Providing a way to inject modules into that graph from within the compartment allows a module to interfere with the linkage of its peers.
22:27
<Kris Kowal>
And that hazard exists regardless of whether or when we reify the Compartment/Loader object.
22:31
<Kris Kowal>
Inevitable bike shed from which there is no escape: “specifier” is heavy. Maybe this should be “to”, the dual of “from”.
22:41
<littledan>
yeah, I'd say that when there's a host loader, you shouldn't be able to just push a specifier into the module map
22:42
<littledan>
so I don't understand the second line of your example
22:42
<littledan>
(I don't really understand how it works even if you have a custom loader)
22:43
<littledan>
I haven't done as detailed a look at the current state of the compartments proposal as I should
22:44
<littledan>
isn't there the same order dependency as if you did import('x.js')?
22:48
<Kris Kowal>
Yeah, let me just excerpt the relevant bit of the proposal.
22:48
<Kris Kowal>
A module descriptor is shaped like {record, specifier, importMeta}.
22:48
<Kris Kowal>
Where record is a static module record, or by any other name just as sweet.
22:49
<littledan>
(is this written somewhere, or is it from discussion after writing took place?)
22:49
<Kris Kowal>
Module descriptors are landed in the proposal README, yes.
22:50
<Kris Kowal>
That is, {record, specifier, importMeta} is one of the shapes in the union, and it’s the one I think most sensibly corresponds to a module block after our meeting this morning.
22:51
<Kris Kowal>
I was of the opinion that blocks might better correspond to static module records, but let’s say I’m tentatively convinced that module descriptors are more useful and do not preclude other motivations I’d had in mind.
22:51
<littledan>
personally I didn't come to a clear conclusion on what module blocks would correspond to after the meeting
22:52
<Kris Kowal>
Sure, tentative opinion. Let’s assume for purposes of discussion.
22:52
<littledan>
also I'm having trouble finding that shape in the union, or maybe I'm looking at the wrong union
22:52
<littledan>
is "instance" a name for specifier?
22:53
<Kris Kowal>
Take the first shape in the union.
22:53
<Kris Kowal>
Then add "specifier" ad hoc since module blocks would need that. There’s a PR that would add it for other reasons.
22:54
<Kris Kowal>
Elsewhere the specifier is implied because the descriptor is value side of a key value pair.
22:54
<littledan>
which PR should I be looking at?
22:54
<littledan>
I'm still not sure what the specifier should be for a module block with no explicit name
22:54
<Kris Kowal>
Or in the case of a loadHook(Specifier) => Promise<ModuleDescriptor>, implied by the argument
22:54
<Kris Kowal>
that is a good point.
22:55
<littledan>
I think we run into funny cases if you're allowed to go and claim a specifier and then imperatively insert that into the module map from inside the compartment. I don't think you should be allowed to do that.
22:56
<Kris Kowal>
I concur.
22:56
<Kris Kowal>
And that actually sums up the argument I’m clumsily building.
22:57
<Kris Kowal>
And sways me back to module {} instanceof StaticModuleRecord
23:00
<littledan>
OK, well, if module blocks were to be added first, we'd have to think about what's observable
23:00
<littledan>
and the two observable things I can think of are 1) import.meta, and 2) what happens when you import() the same module block twice
23:00
<littledan>
I think module blocks have a name, but it's a gensym
23:01
<Kris Kowal>
Right, and gensyms don’t transport.
23:01
<littledan>
yeah, over transport it makes a new one
23:01
<littledan>
so structured clone is approximate
23:01
<littledan>
and each time you postMessage a module block, you get a new copy on the other hand
23:01
<Kris Kowal>
Which means different invariants locally and remotely. That’s a footgun.
23:01
<littledan>
but, import.meta on the web does transport, and it should for this case
23:02
<Kris Kowal>
import.meta is host-defined and doesn’t transport reliably.
23:02
<littledan>
Which means different invariants locally and remotely. That’s a footgun.
we're trying to make design tradeoffs; I'm not really interested in trading jabs of reductio ad absurdum
23:02
<Kris Kowal>
Also, import.meta tends to be a function of host-defined behavior that could vary between the sender and receiver.
23:02
<littledan>
import.meta is host-defined and doesn’t transport reliably.
we're talking about what structured clone does, which is also host-defined
23:03
<littledan>
Also, import.meta tends to be a function of host-defined behavior that could vary between the sender and receiver.
hmm, could you say more about this scenario?
23:03
<Kris Kowal>
Pardon, no jab intended.
23:04
<littledan>
in my mind, preserving the base address for relative specifier resolution is essential for module blocks
23:04
<Kris Kowal>
I should say, I personally value the avoidance of that particular footgun over the convenience of pushing a module block over import, and that is partially informed because I think the same ends can be achieved by other means.
23:05
<littledan>
Oh, let's go into discussing those other means
23:07
<Kris Kowal>
So, I would concede that it is both possible and convenient in some cases to be able to rely on the assumption that a pair of module loaders have the same resolution semantics. In that situation, the pair of loaders can reliably arrive at equivalent import.meta for the same specifier, except when the specifier is a gensym.
23:09
<Kris Kowal>
Taking that thought a little farther, I also think having gensyms for module specifiers is not dangerous unless module blocks can be imported, though I’ll grant that module fragments attempt to cross that bridge.
23:10
<littledan>
well, the purpose of module blocks is indeed to be imported
23:10
<Kris Kowal>
As opposed to merely executed?
23:10
<Mathieu Hofman>
and each time you postMessage a module block, you get a new copy on the other hand
I believe that is still an open issue. I think surma was advocating for preservation of identity
23:11
<littledan>
I believe that is still an open issue. I think surma was advocating for preservation of identity
Ah, thanks, I wasn't sure where that landed
23:11
<littledan>
As opposed to merely executed?
I don't know how to interpret this question
23:11
<Kris Kowal>
Oh, you mean imported for the effect of being executed.
23:11
<Kris Kowal>
I mean imported for the effect of being linked into another module’s environment record.
23:11
<littledan>
the module blocks proposal did not add a concept of "just executing" a module; you use them by importing them
23:12
<littledan>
yeah they can't be imported from an import statement
23:12
<littledan>
just dynamic import or host APIs that do the same
23:12
<littledan>
oh I see what you meant
23:13
<Kris Kowal>
Consider an alternate view: what if all modules including module blocks must have a specifier.
23:14
<Kris Kowal>
In that world, identity of the module instance is moot.
23:14
<littledan>
well, I got a lot of pushback for that design in module fragments
23:14
<littledan>
since it would have this same "impersonation" effect
23:14
<Kris Kowal>
Module blocks become considerably more useful too.
23:14
<littledan>
well, I just don't know how to respond to that concern
23:14
<Kris Kowal>
They become useful for modeling bundles of interlinked functionality.
23:15
<Kris Kowal>
That is, a working set can be captured and transported with module blocks.
23:15
<littledan>
well, sure, they are unified with module fragments, whose job is that
23:15
<littledan>
and yes I was hoping that we'd find a way to make module fragments transportable as well
23:15
<Kris Kowal>
The impersonation problem isn’t because they have specifiers, it is because the specifiers have to be pushed in with a dynamic import or compartment.import.
23:16
<littledan>
however, we actually got stuck on the mechanics of this exact transportability issue when we discussed module fragments previously
23:16
<Kris Kowal>
As opposed to being associated with a specifier by being used in the response to a loadHook for a specifier.
23:16
<littledan>
The impersonation problem isn’t because they have specifiers, it is because the specifiers have to be pushed in with a dynamic import or compartment.import.
I'm not following
23:20
<Kris Kowal>
Moment. I’m internalizing your model for the roles of module blocks and fragments.
23:21
<Kris Kowal>
To recap, you’ve refreshed my memory about module blocks having a gensym for its specifier.
23:21
<Kris Kowal>
This means that my presentation this morning was framed more in terms more akin to module fragments.
23:23
<Kris Kowal>
That means that I do not have proposal for how to represent a gensym module block.
23:24
<littledan>
so, my initial proposal for module fragments is that you'd do, like, module "#foo" { ... } import "#foo"; and the host would just connect the dots as a normal module specifier
23:24
<Kris Kowal>
But I agree that for import(moduleBlock) to work, moduleBlock needs to capture the referrer module specifier in addition to the static module record.
23:24
<littledan>
this was rejected because people said, it's weird to step on the specifier space like that and create ambiguities/an order-based resolution
23:25
<littledan>
But I agree that for import(moduleBlock) to work, moduleBlock needs to capture the referrer module specifier in addition to the static module record.
and this is true for module fragments as well
23:27
<Kris Kowal>
So, I think we can agree that the module blocks in my presentation are something else.
23:27
<Kris Kowal>
Neither module blocks as proposed nor module fragments as proposed.
23:27
<Kris Kowal>
Let’s tentatively call it a “static module block” and as such would be reified as StaticModuleRecord.
23:28
<Kris Kowal>
I’ll throw up a strawman syntax static module {} just so we don’t confuse them.
23:29
<Kris Kowal>
A static module block doesn’t capture its referrer or import.meta.
23:31
<Kris Kowal>
And it’s the virtue of a static module block that it’s transportable and its identity doesn’t matter.
23:34
<Kris Kowal>
(Riffing a gist)
23:36
<Kris Kowal>
This would be the module block behavior through the lens of compartment with a static module block https://gist.github.com/kriskowal/bc9d74a245853d88b7fdd6e4f412c31b
23:43
<Kris Kowal>
And I believe the example from the presentation this morning more closely addresses the module fragment motivating use cases, but notably doesn’t require the static module blocks to carry a specifier. The specifiers are keys in the transported map.
23:44
<littledan>
I would say that module fragments each have gensym'd specifiers as well ,but they can refer to each other in a little mini-map that can be transported
23:44
<Kris Kowal>
I’m thinking module blocks might be coherent with these, in a way that would let them land first.
23:45
<littledan>
but then when they refer to a string specifier, it's resolved on the other side directly
23:46
<Kris Kowal>
Mini-map is a good way to put it.
23:47
<Kris Kowal>
Particularly because the mini-map needs to be transported together in order for it to be coherently linked.
23:47
<littledan>
yes
23:48
<Kris Kowal>
That’s a little tricky because it’s still using string specifiers for the linkage that participate in the destination loader according to its resolver semantics, which are not necessarily the same as the sender.
23:49
<Kris Kowal>
Maybe they would overshadow the specifiers in the target graph.
23:49
<littledan>
Maybe they would overshadow the specifiers in the target graph.
I think this is an intuitive answer given how module fragments reference each other "lexically"
23:50
<littledan>
like module x { } module y { import x }
23:50
<Kris Kowal>
Or maybe they need a notation that allows the gensyms to be expressly separate from the namespace of the receiver.
23:50
<Kris Kowal>
Yes, that’s coherent.
23:50
<Kris Kowal>
Taking advantage of the distinction between x and "x".
23:51
<littledan>
for import.meta, maybe we say that module fragments and blocks have literally the same import.meta as the surrounding lexical context. This would complete the loop on not calling into compartment hooks
23:52
<littledan>
(like, actually the same object identity)
23:52
<Kris Kowal>
I think we’re at least in agreement that the module proposal and module fragment proposal would not call compartment hooks!
23:52
<littledan>
well, this had been a blind spot in my design thinking; I agree on that goal but wasn't sure how it'd work out
23:54
<Kris Kowal>
This also would strengthen the case for having a globalThis.Loader instead of wiring one together from globalThis.ModuleInstance. The loader would be doing a lot of lifting for module blocks and module fragments.
23:54
<littledan>
I hadn't followed that discussion
23:56
<Kris Kowal>
I’m at a bit of a loss for what the value type would be for module blocks and fragments.
23:57
<littledan>
as a placeholder, we could refer to it as ModuleBlock for now
23:57
<littledan>
we know what it has in it, right?
23:57
<littledan>
each has a gensym, an import.meta, and a closed-over mini-map (of gensym -> ModuleBlock)
23:57
<littledan>
is that right?
23:58
<Kris Kowal>
It also has a referrer specifier.
23:58
<littledan>
what is that? isn't that the gensym?
23:58
<Kris Kowal>
No, it’s for resolving stringy imports.
23:59
<Kris Kowal>
Presumably inherited from the surrounding module instance.
23:59
<Kris Kowal>
It doesn’t have a StaticModuleRecord.