chansey97
2021-10-22 08:26:55

@notjack I agree with the point that > making compilation units larger than one file What I’d like is not two mutually-recursive modules, but a big module which could be written in two files.


samth
2021-10-22 13:55:05

I don’t think “compile multiple files together” helps that much. The problem is that you can’t get actual modularity, because what things are exported by one module could, in this scenario, depend on the definitions in the other module. You would have to have a linearization the way top-level forms in a single module are linearized, and it would have to cross between modules. So you’re basically back to something like include.


rokitna
2021-10-22 22:29:53

Part of what I proposed in rhombus-brainstorming issue 166 was that when an attempt is made to require something from a guest module in a cycle, it’s redirected to the cycle’s host, which has a catalog of all the guests’ exports. The guest itself doesn’t know what it exports, but it knows where to find someone who does.

I think there are other approaches where guests can partially macroexpand to the point of determining what their exports will be, if that’s important. I’m already interested in something this, because I have ideas that would make the migration between a separately compiled module and a collectively compiled cycle guest gradual, where only the parts of a file that actually use cyclic dependencies have to have their compilation deferred.

My ideas here are roughly: Cycle members aren’t directly spliced together; they actually import and export bindings to each other. They don’t get to actually use each others’ macros outside of explicitly declared areas. This allows us to perform partial expansion on each cycle member independently of the others, up to those not-so-expansible areas.

There’s actually a second reason I’m looking into areas of explicitly declared dependency within a module: the compilation and module registry memoization of modules with arguments. With areas of explicit dependency, the presence of a compile-time argument doesn’t have to entirely defeat the module’s separate compilation or load-time memoization. (And as long as Racket has generative type definitions, punctual compilation and memoization are important for more than performance!) So the needed technology for modules with arguments and the needed technology for gradual cyclic dependencies fit together pretty snugly, I think.

In the long term, I would like to use deterministic concurrency for module body macroexpansion. I think this creates a more modular independence between things as a default practice, even if many of them technically need to be compiled or loaded in earshot of each other because of some coordination they’re doing. But that’s a more drastic change, and the above ideas don’t need fully generalized deterministic concurrency, just some amount of partial expansion to break up Racket’s sequentiality. Partial expansion is already how Racket does that, so I think it’s in the spirit of things.


notjack
2021-10-23 01:57:43

@samth that restriction is fine with me, personally. It only matters when the circular references aren’t under lambdas (or other forms of delayed evaluation)