michaelballantyne / syntax-spec

A metalanguage for creating sophisticated DSLs in Racket.
Other
26 stars 6 forks source link

global reference compilers #55

Open quasarbright opened 6 days ago

quasarbright commented 6 days ago

I want to be able to use variables belonging to a binding class from racket without being inside of a DSL form.

Solution:

We should be able to declare a global reference compiler, maybe in the binding-class declaration itself.

(syntax-spec
  (binding-class cell-name #:reference-compiler immutable-reference-compiler)
  ...)

that can set the default value of the reference compiler globally, and with-reference-compilers can override it locally.

Motivating example:

In my reactive programming DSL, I want to have (define-cell c:cell-name body:racket-expr), and then I want users to be able to treat cells as variables where references get the current cell value and set! mutates the cell and updates dependents. I'm using get-racket-referenced-identifiers to statically check dependencies, which is why I want a binding class for cell names. But if they have a binding class other than racket-var, then you can't use cell names outside of DSL forms.

michaelballantyne commented 4 days ago

I'm tempted to suggest that we should get rid of with-reference-compilers altogether and require that reference compilers always be specified with binding classes. They would then act a little bit like host interface compilers, which they do feel somewhat analogous to because they are an entry point from Racket to the DSL.

Reference compilers that need to be context-dependent could then use standard Racket syntax parameters to cooperate between the main DSL compiler and reference compilers.

However, the implementation of get-racket-referenced-identifiers does need the ability to provide the alternate interpretation of references vs the binding class reference compiler. And we may run into other such cases. I suppose we could keep with-reference-compilers as a private and undocumented feature.

Separately, with respect to the design of your reactive programming DSL, it sounds like cell references will end up having different semantics inside a cell body racket-expr vs in the rest of the module? In a cell body they will be reactively updated; outside they will not be. Is that right? If so I'm not actually sure I think references outside of a cell body should work implicitly. It seems like it would be better to be more explicit, so that the difference in semantics is clear. At least for a DSL for students.

michaelballantyne commented 4 days ago

I talked to Matthias and Cameron about this today and both seemed to agree that specifying the reference compiler in the binding class would be an improvement.

quasarbright commented 4 days ago

Yeah I think for most languages, specifying the compiler on the binding class should suffice. And like you said, that reference compiler could use syntax parameters to emulate the behavior of with-reference-compilers.

For the reactive DSL, with the syntax spec implementation, cell variables behave the same inside and outside of cell definitions. The dependency graph is constructed statically by collecting cell references within cell definitions. Updates occur dynamically when a cell's value is mutated.

However, in the procedural and simple macro versions of the DSL, you need to use runtime parameters to dynamically construct the dependency graph during the initial evaluation of a cell's body, which is complicated. We could just require dependencies to be explicitly provided though. That'd eliminate some complexity

quasarbright commented 2 days ago

in my current implementation, with-reference-compilers still exists as usual. we can get rid of it if that makes sense

quasarbright commented 2 days ago

currently, you have to define the reference compiler before you specify it in the binding class, which is unfortunate. not sure how we can get around that