News for hackers. Stuff that matters.
Re:Hotcaml: An OCaml interpreter with watching and reloading by dwohnitmok on Wednesday January 19, 2022 @03:17PM (#29999390)
The thing I'm always curious with hot-reload systems is whether there's a good story for state change. What happens if a `ref`'s type is changed? Are `ref` values preserved between reloads?

EDIT: Ah I just read https://github.com/let-def/hotcaml#synchronous-and-asynchron... so it looks like at least for the synchronous `hotcaml` bit it just completely reloads from scratch so state is not preserved, but I'm curious then how the `hotcaml_lwt` frontend deals with this issue.

Re:Hotcaml: An OCaml interpreter with watching and reloading by def-lkb on Wednesday January 19, 2022 @05:02PM (#30000918)
Both the synchronous and asynchronous frontends preserve as much state as possible (all untouched modules are kept). They differ in the control flow they permit (the asynchronous one being more expressive).

I will try to make a parallel with a simple Makefile-driven project.

In the initial build, all files are built, following a topological ordering of the dependencies. For the Makefile it means invoking some unix command for each intermediate artefact. For Hotcaml, it means parsing, typing, compiling and loading each module.

After that, build is incremental: when a file is modified, only this file and its reverse dependencies need to be rebuilt. Make will keep the existing artifacts that are not out of date. Hotcaml will keep the existing modules that are not out of date. And their state is preserved.

Now, the synchronous frontend is quite like a regular Makefile: a build step is considered done when the build command finishes. The asynchronous frontend allows command to run in the background, like a Makefile that would spawn processes/daemon using the shell & control operator.

In Hotcaml, these threads continue executing concurrently with the reloading process. They can be notified that their "host" module has been reloaded by registering with some runtime service (via a module named Hotlink).

Re:Hotcaml: An OCaml interpreter with watching and reloading by rsstack on Wednesday January 19, 2022 @03:58PM (#30000010)
Check out how Erlang/Elixir/BEAM deal with this. Stateful processes write a state-migration function that's run (new code, old state) when hot reloading the process. Requires some forethought, especially when processes can be updated in any order, but it's really amazing. Of course, when doing hot-reloading in a local development environment and not in production, it doesn't make as much sense.
Re:Hotcaml: An OCaml interpreter with watching and reloading by dwohnitmok on Wednesday January 19, 2022 @04:07PM (#30000150)
Right Erlang has explicit migrations and dynamically-typed image-based languages just persist the state.

I'm curious if there have been any similar things for statically-typed languages.

Re:Hotcaml: An OCaml interpreter with watching and reloading by def-lkb on Wednesday January 19, 2022 @04:44PM (#30000648)
I am the author of Hotcaml.

There is actually some notion of persisting state in it. Reloading is done at the granularity of a module. The reverse dependencies of a module that changed are also reloaded, but the dependencies are not. The runtime state of all modules that are not reloaded is persisted.

Here is an example: https://aws1.discourse-cdn.com/standard11/uploads/ocaml/orig...

The dependency graph is roughly: system layer -> renderer -> slideshow The system layer initializes the window (with SDL) and an OpenGL context. The renderer allocates resources (buffers, fonts, ...). The slideshow only defines the content to be drawn.

In the live code, only the slideshow is modified, so the system and renderer states are not affected.

Doing reloading at the module granularity meshes well with ML semantics: it is a straightforward extension of the "hyperstatic environment" and it preserves type safety and modular abstraction.

A static language that is designed with hot reloading in mind could do better, the generative nature of ML type definitions is not ideal.

I guess that structural type systems permit a finer grained notion of reloading. Actually, a finer-grained notion of persistence and state migration could be built as a library (with some macros) on top of Hotcaml. The important step is to be able to reify type definitions and then to define some notion of "type compatibility" (between old and new modules) by induction on the structure of types. This is a lot of work, but could be built on top of Hotcaml foundations.

Re:Hotcaml: An OCaml interpreter with watching and reloading by dwohnitmok on Thursday January 20, 2022 @02:07PM (#30013169)
> Reloading is done at the granularity of a module. The reverse dependencies of a module that changed are also reloaded, but the dependencies are not. The runtime state of all modules that are not reloaded is persisted.

Ah that makes sense to me, and explains to me why in your linked demo the rotation resets after every color change, but the other stuff doesn't. That does mean though that having the circle not reset after every color change is probably not feasible unless the module order is fairly convoluted right? (because most straightforward ways I can think of organizing the code would have the circle motion as a reverse dependency of the color of the circle).

Re:Hotcaml: An OCaml interpreter with watching and reloading by def-lkb on Friday January 21, 2022 @08:26AM (#30023153)
> having the circle not reset after every color change is probably not feasible unless the module order is fairly convoluted right?

Not necessarily no. The thing is that you could have an early module that implements a framework to manage state. For the circle rotation, it is quite easy, it is a single number. You could do something like:

`let circle_rotation = managed_state "circle_rotation" Float 0.0`

"The rotation of the circle is represented by a float initialized to 0". Then even when your module is reloaded, the hypothetical framework takes care of preserving this piece of state.

Re:Hotcaml: An OCaml interpreter with watching and reloading by munificent on Wednesday January 19, 2022 @04:51PM (#30000751)
The Dart VM supports stateful hot reload and it's used heavily by Flutter developers. There are some kinds of structural changes that necessitate a full restart that wipes state away, but the VM is suprisingly good at migrating the existing objects in the heap to match any changes to the underlying classes and preserve as much state as possible.

https://docs.flutter.dev/development/tools/hot-reload

Re:Hotcaml: An OCaml interpreter with watching and reloading by dwohnitmok on Thursday January 20, 2022 @02:12PM (#30013248)
Right so I think this the approach that most UI frameworks tend to adopt, which is to have a central data store that then is persisted between changes to the view code that generates a view from that store (this is effectively how hot reloading works for things like Redux with Webpack or Elm and I think based on those docs, also how Dart does it).

I'm curious though what happens if you have to make changes to that data store in a statically typed language like Dart, e.g. change the type of a field. The docs there only seem to have a few sentences about that (which I think is talking about a related, but slightly different thing, which is that hot reload allows a whole new host of paths to create state which might've been impossible to ever achieve during the normal, non-hot-reloading operation of an app, including violating certain assumed invariants):

> If code changes affect the state of your app (or its dependencies), the data your app has to work with might not be fully consistent with the data it would have if it executed from scratch. The result might be different behavior after hot reload versus a hot restart.

Does the app crash? Or does it automatically restart with a fresh slate (maybe this falls under the "some kinds of structural changes that necessitate a full restart that wipes state away" you mentioned)? Or is the change ignored? Or is there some degraded "delayed type checking" mode that occurs with hot reload that changes a type into a runtime type guard and causes some sort of exception for anything that requires the field to be a certain type?

Re:Hotcaml: An OCaml interpreter with watching and reloading by munificent on Thursday January 20, 2022 @02:23PM (#30013445)
> which is to have a central data store that then is persisted between changes to the view code that generates a view from that store

You may think of it that way conceptually but the language and VM don't think of it that way. It's all just objects in memory in the heap. Architecturally, there's no real separation between persisted and non-persisted state.

> Does the app crash? Or does it automatically restart with a fresh slate (maybe this falls under the "some kinds of structural changes that necessitate a full restart that wipes state away" you mentioned)? Or is the change ignored?

I'm not an expert on the details, but I think it simply won't do the hot reload if it determines that it can't do so safely. It's up to the user to then choose to do a full restart and wipe the state if they want.

Re:Hotcaml: An OCaml interpreter with watching and reloading by sitkack on Thursday January 20, 2022 @03:23AM (#30006253)
I was going to make a similar comment about reload() in Python. One dev technique out of the many available is to have your code being edited in your editor while in another terminal window, using an ipython repl to drive it. Currently one would need to `from importlib import reload` and of course ipython itself has

https://ipython.readthedocs.io/en/stable/config/extensions/a...

Launch ipython like you would `pdb`

https://pypi.org/project/ipdb/

*edit to @dwohnitmok as the author of Crafting Interpreters mentioned, it really works pretty well in practice. And for cases where I was changing enough state that it bails out, you can either set a breakpoint in a test or create a little closure to build up the right state and then pass back an fn to step through in ipython.

Infact, this dev style reinforces an immutable nearly functional data centric programming model. With that model, changes to code won't impact the data, so reloads are actually rare. Have shallow reference chains, use value types in simple containers and lots of problems kinda melt away.

Ha! https://news.ycombinator.com/item?id=29965226 the highest rank post on Google search for that quote is less than 3 days old. Know we know why results are so bad!

Re:Hotcaml: An OCaml interpreter with watching and reloading by dwohnitmok on Thursday January 20, 2022 @02:18PM (#30013354)
Fascinating.

So the main thing I'm curious about is the exact mechanics of this:

> And for cases where I was changing enough state that it bails out

What exactly does "bailing out" entail?

Re:Hotcaml: An OCaml interpreter with watching and reloading by sitkack on Thursday January 20, 2022 @11:01PM (#30018972)
It isn't something I explored that deeply. When a reload fails, you know about it and you just reload the program and continue. It could manifest itself in lots of ways, any of which I don't have off the to of my head.
Re:Hotcaml: An OCaml interpreter with watching and reloading by scoopr on Thursday January 20, 2022 @02:09AM (#30005719)
Also Visual Studio does `Edit and Continue`[0], which I believe works by patching function prologues to jump to another location.. I don't think it handles structure changes all that gracefully, but honestly I haven't used it that much to know for sure.

[0] https://docs.microsoft.com/en-us/visualstudio/debugger/edit-...