00:00
<littledan>
oh, right
00:00
<littledan>
wait I thought it did have a static module record?
00:00
<Kris Kowal>
The mini-maps are interesting because they contain subgraphs, some of which are potentially cyclic.
00:01
<littledan>
yes
00:01
<Kris Kowal>
Thankfully you can arrive at a deterministic ordering of the subgraphs by sampling in order of appearance in the source.
00:02
<littledan>
well, presumably we'd do this ordering with the same algorithm we use for normal cyclic graphs (depending on where you start with in the cycle)
00:03
<Kris Kowal>
Yeah, maybe. There might be optimizations that are possible only if the entrypoint doesn’t figure. But that doesn’t surface to JavaScript regardless.
00:03
<littledan>
well, it's readily observable, unfortunately
00:03
<Kris Kowal>
As for StaticModuleRecord…
00:05
<Kris Kowal>
StaticModuleRecords would hang off the nodes of the mini-graph, not off the ModuleBlock.
00:06
<littledan>
huh, that's a way to represent it, I guess more normalized and less cyclic of a structure than I was imagining
00:06
<littledan>
sgtm
00:07
<Kris Kowal>
They don’t correspond to a document per se. Not something you could fetch.
00:07
<Kris Kowal>
Except perhaps in a compiled form.
00:08
<Kris Kowal>
One of the interesting things about lexical linkage is that the compiler can erase the names.
00:09
<littledan>

BTW note that the mini-graph is actually something like a singly linked list of maps, following a scope chain, as you could have (and this is stupid code but still possible),

module foo { }
module bar { }
if (true) {
  module foo { }
  module baz { }
  module bing { import foo; import bar; }
}
00:10
<littledan>
also line 6 could've been eval("module bing { import foo; import bar; }") -- this scope chain needs to be reified at runtime if there's a direct eval
00:11
<littledan>
(I feel pretty strongly that you should be able to use module blocks/fragments in sloppy mode code)
00:11
<Kris Kowal>
Are we in agreement that every time import(ModuleBlock), it’s getting fresh instances of the nodes of its minigraph?
00:12
<littledan>
hmm, I imagined otherwise, that the gensym would be cached
00:12
<littledan>
and the duplication would only happen across postMessage
00:12
<Kris Kowal>
So import(ModuleBlock) would behave differently than e.g., shadowRealm.importValue(ModuleBlock)
00:13
<Kris Kowal>
Versus, compartment.import(ModuleBlock), maybeAgentSomeday.import(ModuleBlock)
00:13
<littledan>
So import(ModuleBlock) would behave differently than e.g., shadowRealm.importValue(ModuleBlock)
these both go to the host's module map
00:14
<littledan>
I mean, for the "fetch" part
00:14
<Kris Kowal>
Yeh, those both being local.
00:14
<littledan>
Versus, compartment.import(ModuleBlock), maybeAgentSomeday.import(ModuleBlock)
I don't really know what these statements mean
00:14
<Kris Kowal>
I suppose it’s here nor there for me.
00:15
<Kris Kowal>
Just that if a module block has to be serialized and deserialized, you necessarily get a fresh batch of gensyms, so the invariants are different.
00:15
<littledan>
oh yes I agree with that
00:15
<littledan>
I mean at least this is what I was picturing
00:16
<Kris Kowal>
I don’t like there being difference but it concede it’s a value judgement.
00:16
<Kris Kowal>
And I think we agree it’s an orthogonal concern to compartments.
00:17
<Kris Kowal>
That is, I’m convinced that module blocks and fragments proposals are orthogonal to compartments.
00:17
<Kris Kowal>
And that I’ll want to carve a hole for static module {} which would be different.
00:18
<littledan>
yeah, or put differently, I think we have ideas about how this should go that works out orthogonally
00:18
<Kris Kowal>
Yes.
00:18
<littledan>
I'd suggest that, as a hack, you could just make a method on a module block which "projects out" the static module record
00:18
<Kris Kowal>
There are certainly ways that would cross the streams :-)
00:19
<Kris Kowal>
That’s a good idea.
00:19
<littledan>
(and I guess it's an error if that leaves you with a free reference to another module fragment)
00:20
<Kris Kowal>
The StaticModuleRecord is opaque and doesn’t close over source, so the fact that the source is a compiled artifact of some kind is moot. That just raises questions about how it would be represented on the wire if it were transported.
00:20
<littledan>
wouldn't source code typically work OK?
00:21
<Kris Kowal>
I don’t think we have to worry about getting that far. I presume you’d get a ReferenceError before you had a handle on the ModuleBlock.
00:21
<Kris Kowal>
It wouldn’t be source code, but object code (reconstructed source code).
00:21
<littledan>
I don’t think we have to worry about getting that far. I presume you’d get a ReferenceError before you had a handle on the ModuleBlock.

hmm, I don't see why, here's an example:

module foo { }
(module { import foo; }).project()
00:22
<littledan>
the .project() method has to be responsible for throwing the error
00:22
<Kris Kowal>
Let’s just say that’s spelled get record()
00:23
<Kris Kowal>
I don’t see the error in the example.
00:23
<Kris Kowal>
import foo is satisfied, no?
00:23
<littledan>
well, would the static module record already have a mini-map?
00:23
<littledan>
I thought you were saying it shouldn't
00:24
<littledan>
I guess it probably should
00:24
<Kris Kowal>
I think the mini-map is a product of compilation.
00:26
<Kris Kowal>
And, provided we distinguish lexical imports from stringly named imports (which I take to be necessary for the proposal to work, much less entangle itself with compartment concerns), then a module block can throw a ReferenceError if it contains an unmet lexical import.
00:26
<littledan>
hmm, I thought we'd make the lexical errors be early
00:26
<Kris Kowal>
I think we’re agreeing.
00:27
<Kris Kowal>
Oh, you mean even earlier. Yes, that’s possible and good.
00:27
<Kris Kowal>
Like, compiling the surrounding module would fail.
00:28
<littledan>
exactly
00:28
<Kris Kowal>
Yeah, that follows.
00:28
<Kris Kowal>
And if you succeed, the compiled module contains the skeleton of all possible module block graphs, out of which you could project a record for each on demand.
00:29
<littledan>
And if you succeed, the compiled module contains the skeleton of all possible module block graphs, out of which you could project a record for each on demand.
Hmm, I don't understand this
00:29
<Kris Kowal>
And the records could be reconstituted to source strings, flattening just the nodes that get mentioned.
00:29
<littledan>
so, I'm kinda leaning towards, StaticModuleRecord does have the minimap
00:29
<littledan>
is that too weird?
00:30
<littledan>
so this goes back to, a ModuleBlock is a StaticModuleRecord + a referrer base + an import.meta object + a gensym that allows it to be used as a key in a minimap
00:31
<littledan>
and each StaticModuleRecord has a minimap which maps gensym -> ModuleBlock
00:31
<littledan>
this is the "more circular, less normalized" option I was mentioning above
00:32
<guybedford>

if I might jump in, that framing feels to me like a much simpler model for fragments, in that the rest of the loader pipeline can work as it does already

effectively these are hard compilation-time resolution linkage. something like [[HardResolutions]] = [SourceTextA, SourceTextB] they can simply even be an ordered list actually

00:32
<Kris Kowal>
Yeah, I agree.
00:33
<littledan>
(guybedford (Guy Bedford): Are you saying you like the design?)
00:33
<guybedford>
yes I like the approach, although would have some technical clarifications further
00:33
<Kris Kowal>
I think what this means is that a source text has a corresponding StaticModuleRecord, which can be partitioned into smaller StaticModuleRecords, one per module block.
00:34
<guybedford>
I'm suggesting the internal ecma-262 object that backs this simply has a list field
00:35
<guybedford>
that points to other similar objects
00:35
<littledan>
oh, are you suggesting that the internal datastructure simply be circular instead of indirecting through gensyms and a map?
00:35
<guybedford>
yes
00:35
<littledan>
oh that makes sense
00:35
<littledan>
I agree that that would be valid
00:36
<littledan>
I think full implementations would still need to maintain some maps around in case of eval, though, unfortunately
00:36
<littledan>
but yes, the fact that this representation is possible makes the design feel clean
00:37
<guybedford>
I think full implementations would still need to maintain some maps around in case of eval, though, unfortunately
would be interested to dig in further at some point, but won't sidetrack further!
00:37
<littledan>
Kris Kowal: guybedford , you two have been very helpful here; thank you so much for this discussion
00:38
<littledan>
I really didn't know where to go next with module blocks/fragments, but this made it very clear
00:38
<Kris Kowal>
Agreed and thanks for helping me understand the differences.
00:39
<littledan>
with module blocks and fragments so thoroughly unified (I initially suggested the two names so that they wouldn't be conflated, back when the concepts were a bit different), do you think we should use a different name? Like, "inner modules", where there are both named inner modules/inner module declarations and anonymous inner modules?
00:39
<littledan>
also presumably a module block expression should be able to provide a name for purely local use, as functions and classes do
00:40
<Kris Kowal>
I’m still pondering implications myself.
00:41
<Kris Kowal>
I think static module block might evaporate given (module {}).record being a thing.
00:41
<guybedford>
Definitely +1 to unifying naming and structures, and extending optional naming to module blocks, although hopefully specifications can stay separate?
00:41
<Kris Kowal>
Especially given that would project the relevant subgraph.
00:42
<littledan>
Definitely +1 to unifying naming and structures, and extending optional naming to module blocks, although hopefully specifications can stay separate?
I think the first step would be to developing the module fragments spec text, and then a strict subset which is just the anonymous cases (for module blocks) can be sorted out
00:43
<Kris Kowal>
I value the holistic view of blocks being a degenerate case of fragments and don’t particularly care about the layering. If it helps deliver incrementally, I’d say whatever works.
00:43
<littledan>
they didn't used to be degenerate! they used to be based on the same concept of inserting in a certain class of specifiers into the module map!
00:43
<littledan>
but yes that's what they are now, degenerates :(
00:44
<Kris Kowal>
This is why mathematicians can’t have friends.
00:44
<Kris Kowal>
To be clear, this is also why systems programmers can’t be allowed near children.
00:46
<Kris Kowal>
But perhaps that’s hyperbole.
00:47
<littledan>
have a good evening everyone
03:04
<Kris Kowal>

For those who arrive here and find a vast scroll backlog, littledan had a long conversation where we concluded that module blocks and module fragments could be framed in a way that makes them orthogonal to compartments, such that the order in which the proposals land isn’t coupled.

We concluded that importing a module block or fragment would not involve the loader hooks and would not introduce any module specifiers to the module graph.

This presumes that module blocks are a special case of module fragments and that fragments are named lexically. So, import x rather than import 'x'. The latter is the purview of the loader hooks. The former is the purview of a lexical binding to module x {}. Module blocks have a corresponding static module record, which itself consists of its own module block and its transitive lexically imported module blocks, but also capture the module referrer specifier and import meta.

There remain some free variables in the idea, but that I believe summarizes the consensus we arrived at.

03:31
<Kris Kowal>
Oh, and I think that the proposals are coherent. Module blocks, including module fragments, would at least satisfy the shape { record, importMeta } so it could be used as a module descriptor in a Compartment loadHook. (I am assuming “record” gets renamed before the proposal’s ink dries, but whatever the names, they’d be the same.)
18:54
<shu>
hmm, where should we publish the call notes?
19:16
<Kris Kowal>
I think it’s sufficient to have a rolling agenda document attached to the calendar for discovery purposes. Could link the notes from there. The notes are detailed enough that probably to have separate meeting notes docs for each session.
19:16
<Kris Kowal>
Similarly, the SES meeting links recordings to the rolling agenda document.
19:16
<littledan>
I think it ends up being more accessible if notes are published in a markdown file somewhere, as Shu has been doing in some other meetings that he runs
19:17
<littledan>
we can share the permission to read the notes more widely than the permission to edit old minutes
20:19
<shu>
i don't want to use just the document because it's world-editable for notetaking
20:19
<shu>
yeah, what dan said