Module system: Scheme48 vs R7RS

Studying the Scheme48 module system

I wrote a while back that the first program I’d like to run on Kiwi would be TinyCLOS, now that I have KLOS going on Kawa, I’m gonna revise what I said: I think the first program that Kiwi should run ought to be the Scheme48 module system (and by extension, its command processor).

Taking a break from KLOS hacking this weekend, I re-read JAR’s paper on the Scheme48 module system this weekend. The section on configuration mutation grabbed my attention in particular.

Reading the Scheme48 manual, it’s clear that the module system and command processor really work together as a whole. One thing I noticed trying to read the module-system code is that due to bootstrapping, since Scheme48 is built on top of Scheme itself, there’s also a fake version of the module system to be loaded on systems that don’t have a module system.

Metacircular bootstrapping is necessarily more involved

Things get complicated, and often necessarily repetitive, when you need to bootstrap a system. There needs to be a base, fake (or at least simplified), definition to get the system running, and then another, more complete, aka. real implementation is repeated once more to get to the full semantics later on. This makes the definitions read somewhat circularly.

I also noticed this when I was reading the code for the Thomas Dylan->Scheme compiler. Since Thomas just compiles Dylan into Scheme, its class and generic-function definitions are a lot simpler than TinyCLOS’s.

I wonder if I side-step the issue and implement the underlying structures only in Kotlin, maybe I can arrive at the simpler (Thomas-like) implementation of the module system in Kiwi.

Differences between Scheme48’s module system and R7RS

The two module systems are largely the same, modulo some differences in naming (define-structure in S48 vs. define-library in R7RS), but there are two parts that stand out: explicitly named interfaces and the marking of syntax definitions and exports.

As noted in the S48 manual, explicitly named interfaces are not strictly necessary, but there are good reasons why it’s nice to have them named, such as the ability to control the visibility of an identifier during interactive development.

Andrew has ported parts of the R7RS module syntax on top of Scheme48 for his Precheme work, so I can make use of that if I decide to just implement the S48 module system.

One thing that I have yet to figure out is what it means to have (or not have) the :syntax and for-syntax markers in the definitions. Scheme48 has them, R7RS doesn’t.