Someone told me recently that that hotloading is impossible in Racket, but I feel like I do the every time I use DrRacket, or change a script in Quickscript? What is the distinction I’m missing here? (I’m not restarting DrRacket every time I hit run?)
And if I can do that in DrRacket, why not in the webserver?
There’s no good basis for this claim. dynamic-require
is all you need for hotloading (unless my definition doesn’t match theirs)
Thank you @soegaard2
You need to create new namespaces too, otherwise the second dynamic-require doesn’t do anything (I know you know that, @laurent.orseau)
Hot loading requires somewhat more work in Racket than in Closure or Common Lisp
Is that a immutability issue? - in the sense that it makes for safer code?
Also usability like the repl
It’s mostly that there’s no way to change the definition of a module after it’s loaded
Sounds like a good thing?
In Clojure or CL, all variable references to top level variables are in directed though effectively a big mutable table
And redefinition just mutates that table
So redefinition affects earlier definition
Just like in the Racket repl
If you do everything with the repl and load in Racket then it’s just as easy to do hot reloading
Lexical scope doesn’t apply?
For lexical variables, yes, but for top level definitions it’s not clear what that means
Eurghh!
I’d always assumed order counted
Then you couldn’t define mutually recursive functions at the repl
What you suggest is how the ML repl typically works
Ahh
So much to learn.
@samth can you suggest a resource I can use to learn more about this ? ( is there a text?)
No, there’s no text I know about for repls
Thanks anyway.
What I mean is that within a class
form (from racket/class
) a function application with a method is transformed to (send this method args ...)
similarly for variable references for fields.
I’m assuming dynamic-require
+new namespace is what is going on when you hit run in DrRacket or load a new quickscript without restarting DrRacket each time ? (in the same way https://github.com/tonyg/racket-reloadable\|https://github.com/tonyg/racket-reloadable uses dynamic-require)
DrRacket more directly calls eval because it isn’t running a file on disk, but yes
Thank you:grinning:
That’s what quickscript uses indeed. MrEd Designer also uses dynamic-require
to load the plugins, but it doesn’t use namespaces since the plugins don’t need to be reloaded. (this allows for designing new widget classes without touching the core of mreddesigner)
I forgot about MrEd Designer!
“Hyper-static global environments” come up in this kind of conversation. So do fexprs.
Both approaches lead to better consistency between functions and macros: Fexprs make them both reloadable, and hyper-static global environments make neither of them reloadable. (I’ve also heard of people making both reloadable without resorting to fexprs, by keeping track of macro uses and re-expanding things when the macro is redefined.)
I’m not sure what hyper-static global environments are, but fexprs are really not related to reloading (and a bad idea besides)
While I probably agree at the “bad idea besides” level, I don’t see how they could be unrelated. With compile-time macroexpansion, existing macro calls “still use” the old definition because they already used it in a compile-time step that was taken care of before the redefinition even took place. An easy-to-propose way to “fix” this is to make macro calls as lazy as function calls: Have them wait until just before a call is evaluated (at run time) to look up the macro’s definition, so that its latest redefinition can be taken into account. That’s more or less what fexpr calls do.
but this just restates the issue for functions. the central problem of the top level is what do references mean — do the refer to the thing defined at the time of definition, or do they “see” redefinitions. the question is “do we want everything to be indirected through a big mutable table so that it can be changed at any time”, and whether or not to have fexprs is orthogonal.
Fexprs are one popular way to make macros redefinable (inasmuch as it’s at all popular for macros to be redefinable), and mutable environments are one popular way to make functions redefinable. There are other ways that I think are preferable to either one of these, such as listening for redefinitions and triggering recompilation of things that call them.
It seems to me the topic at hand is hot reloading of code. Depending on what kind of code someone wants to reload, it could contain both function and macro definitions. But I’ll set the macro side of this aside now, so that I’m not continuing to defend fexprs. :-p
At a basic level, if the user intends to redefine something, then they’re contradicting the user intent they expressed before. The question “what do references mean” doesn’t have any simple answer in this situation; whatever the user intended when they wrote those references in the first place is no longer what they want them to mean now.
And yet this kind of change in user intent can never be dismissed as “hopeless” because it’s often pretty normal and healthy to change one’s mind. It’s nice to have tooling features that accommodate short-term user mistakes (e.g. undo), help them visualize the choices they’re making, help them migrate from old choices to new ones (e.g. database migrations and API versioning), and build up their long-term ability to build custom tooling in anticipation of their own future intent-expressing needs.
When I imagine a user experiencing things like undo support, guided choice-making, and data migration in the process of redefining something in a REPL, I’m not sure that “do we want a mutable table” is the full extent of the question.
Still, since when does a REPL have all those niceties? Can I be sure the user actually wants a data migration tool in the middle of their REPL section? It could easily be premature abstraction. Because of that, I don’t think I can hold an opinion very strongly here; there’s just a design space, and I’m more hopeful about some points in the space than others.
In the meantime, I’m not too familiar with the ML REPL, but I think a hyper-static global environment and what the ML REPL does are the same thing. It’s just a name I wanted to put out there to connect it to other discussions that exist on the same topic.