Thanks for exploring this!

I was tempted down this path earlier this year because I was trying to 
future-proof my structure type definitions by making them cross-phase 
persistent. I see no innate reason for them not to be, so I figured I'd put 
in the effort early and avoid having to make a breaking change later on.

In the end, it turned out I wanted my structure type definitions to use 
certain things like `gen:custom-write` and `gen:equal+hash` that aren't 
supported by cross-phase persistent modules. In fact, the cross-phase 
persistent modules in Racket seem to have very few *specified* exports at 
all[1][2][3], so I was afraid I might rely on some unspecified behavior 
today and find it missing tomorrow. On top of that, even a cross-phase 
persistent module doesn't "persist" across multiple module registries, so 
it doesn't fully match my expectations.

This logger approach looks like it could achieve something just as 
"persistent" as a cross-phase persistent module (unfortunately not 
persisting over multiple module registries or multiple loggers), and with 
very little use of unspecified behavior along the way (although I see you 
still rely on a few exports of `#%kernel`, particularly `gensym`). Of 
course, if it runs up against the separate compilation guarantee, this 
might be the kind of specified behavior that's ruled to be a specification 
error someday.

As for what to do about it...

It seems to me that the separate compilation guarantee's exception for 
"external effects" means it's not a very strict guarantee. As long as 
compile-time code can interact back and forth with the outside world, an 
occasional programmer may rig up a system in the outside world that serves 
no purpose except to be an accomplice in breaking the guarantee.

If the root logger can be that accomplice, should it just be considered 
external (by fiat), essentially documenting that it's an exception to the 
guarantee? I don't suppose many other external effects make it easy to 
round-trip object references in a memory-safe way, so this might make it a 
bit special.

On the other hand, the design of the logging interface seems especially 
prone to abstraction leaks. Isn't logging often thought of as an 
implementation detail? I wouldn't expect to be able to listen to a module's 
logs unless I had power over its code inspector (or something like that).


[1] "The exact set of function bindings exported by `racket/kernel` is 
unspecified and subject to change across versions. 
<https://docs.racket-lang.org/reference/Kernel_Forms_and_Functions.html>"

[2] "Primitive modules with names that start with #% [like `#%kernel`] are 
defined, but they are not meant for direct use, and the set of such modules 
can change. <https://docs.racket-lang.org/reference/running-sa.html>"

[3] Admittedly, certain identifiers like `#%declare`, `#%provide`, 
`define-values` and `gensym` are documented to be part of the accepted 
grammar of cross-phase persistent modules, so I suppose it's strongly 
implied that at least some cross-phase persistent modules exist that export 
these bindings.


On Sunday, April 21, 2019 at 3:41:15 AM UTC-7, Alexis King wrote:
>
> Hello all, 
>
> I just published a blog post on defeating Racket’s separate compilation 
> guarantee. While I don’t imagine such a thing is actually a good idea, I 
> think the path to getting there is interesting anyway, and it touches lots 
> of different parts of the Racket system. For those who are interested, the 
> blog post is available here: 
>
>     
> https://lexi-lambda.github.io/blog/2019/04/21/defeating-racket-s-separate-compilation-guarantee/
>  
>
> Comments welcome, 
> Alexis 
>
>

-- 
You received this message because you are subscribed to the Google Groups 
"Racket Users" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to racket-users+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to