4 ms·
Hot Reloading Rust – For Fun and Faster Feedback Cycles
- dymk 4y agoOnly being able to change function implementation (and non generics only at that) seems like a substantial limitation. Its not often I’m quickly prototyping something that would benefit from hot reloading, and not also changing data layout as I’m iterating. I’m curious to see if the sharp edges will soften as time goes on. Mangling structs to be pinned to a particular loaded library version somehow, and injecting indirection where they’re used, would take this a long way. But would probably require compiler support.
- robertkrahn01 4y agoYeah the approach is restricted and more compiler support for this kind of workflow would be incredibly welcome. I wrote this in part to try to get more folks in the Rust community thinking in this direction. The hot-reload support that Zig is planning sounds really exciting and I would love for Rust to have something similar (one can dream, right ;). That being said, you can still go quite some way with this approach. On the one hand, simply being able to twiddle an algorithm into shape is really handy when making a game, visualization or exploring data. On the other hand, you can also serialize state or keep it in a generic form like a serde_json::Value. Serialization of course needs some kind of migration on the part of the code using it (if the data layout changes it loads an old version and needs to convert it to the new form) or defaults for newly added fields/types. However, this is true in general, even in other languages.
- dymk 4y agoLike you say, modeling the interface between the shared library like a Thrift struct (which can be serialized) may be beneficial, and would facilitate adding/removing fields by having e.g. default fields. Or just crash if a non-backwards compatible change is made, e.g. a new field is expected but not present, but ignore fields that are present but no longer expected. I think the other killer feature that this is missing is being able to have a "release" compilation mode that removes the hot reloading entirely, and seamlessly statically links in the library.
- robertkrahn01 4y ago> have a "release" compilation mode that removes the hot reloading entirely Oh that is easy to do thanks to Rust features, see the reload-feature example: https://github.com/rksm/hot-lib-reloader-rs/tree/master/examples/reload-feature https://github.com/rksm/hot-lib-reloader-rs/tree/master/exam...
- dymk 4y agoVery cool!
- forrestthewoods 4y agoIs there any language that supports hot reloading + data layout changes? I’m not sure that even makes sense.
- dymk 4y agoErlang, JavaScript, Ruby, Python come to mind. Dynamic languages which inherently don't expect data to have a statically enforced shape. Doing it in a statically typed language would be substantially harder, and to make it feel "good", probably require lots of tracking of library versions associated with particular data objects or strict isolation of how data passes across the library boundary. I don't think there's a great solution to be had.
- steveklabnik 4y agoThose all don’t let you change your data’s layout: they’re always behind a pointer, no? It’s a uniform representation.
- robertkrahn01 4y agoIn JS for example, if you change the prototype of an object you have effectively changed it's data layout but of course everything is behind a pointer / an indirection. When changing instance or class variables in Smalltalk, the system actually changing the object layout and goes and recompiles code using it. If you are interested in the details: Chapter 5 of [1] explains it a bit. [1] Hirschfeld et al. Assisting System Evolution: A Smalltalk Retrospective. http://soft.vub.ac.be/Publications/2002/vub-prog-tr-02-25.pdf http://soft.vub.ac.be/Publications/2002/vub-prog-tr-02-25.pd...
- steveklabnik 4y agoThanks!
- dymk 4y agoYes, the indirection (and also late binding) is why hot reloading is (somewhat) ergonomic in those languages, but would be difficult to do in Rust (or C++, etc). I think the shared library types would need to be indirected either via compiler support, or some kind of `Hot<T>` wrapper that acts like a `Box<T>` when hot reloading is enabled, and like a `T` in "production" mode to be ergonomic.
- nixpulvis 4y agoJust a quick thought... wouldn't it be a bit more practical to implement this behind some form of "load balancer"-like system at the network/io layer? Are self updating processes really the right abstraction? Seems like it kinda flips reliable build/deploy processes on their head a bit.
- robertkrahn01 4y agoIt's definitely a possibility to design some form of RPC mechanism and have multiple parts of your application run as essentially a distributed system. There would still be the problem that the "main" application part is expecting the rest of the system to behave in a certain way and if it is maintaining state, the state to be in a certain form. So I'm not sure that you would really win much. Also, part of the idea is to make hot-reload as little additional burden as possible. Proper compiler support would be the real solution to that but in the form presented in the article you can at least quickly switch between an efficient static build and a dev version, something that would be hard to achieve with an RPC mechanism.
- ConnorLeet 4y agoSounds like Erlang from what I’ve heard about it
- intelVISA 4y agoAgreed, I made something similar to live patch services w/o downtime and despite being cool I'm not sure I'd recommend it vs. just putting replicated containers behind a load balancer.
- infogulch 4y ago> Are self updating processes really the right abstraction? As a debug tool, absolutely. As as a normal part of program execution in production? A bit sketchy. But that said.... ... what if there was a sure way to directly map your entire program state into the new version and you could be assured that you didn't miss any obscure corner of the state space? Like a borrow checker for transitioning between program versions. That'd be pretty neat.
- deleted 4y ago[deleted]