rune-rs / rune

An embeddable dynamic programming language for Rust.
https://rune-rs.github.io
Apache License 2.0
1.7k stars 86 forks source link

Stateful Hot-Reloading. #33

Closed shekohex closed 5 months ago

shekohex commented 4 years ago

First of all, Thanks for this great project :smile: Could we have at least a Hot-Reloading? I would like to see that built-in the Engine (VM) itself.

An embeddable language into Rust would usually get used into one of these cases (at least):

  1. GameDev 🎮
  2. User Scripting (Plugins). 🔌
  3. Extend The Program logic at Runtime without Requiring Recompiling the whole project.

All of these cases would benefit from Hot-Reloading, especially if we could get a Stateful Hot Reload.

I would like to contribute and push the language and the VM to see this feature happens. 😄

shekohex commented 4 years ago

An Example of language that built around this feature is Mun Language

udoprog commented 4 years ago

So in principle there appears to be very little that prevents you from doing the same kind of hot reloading as was showcased in the Pong demo:

That is if I interpreted what was done in the video correctly. I'd love it if someone could link the source code.

One thing that can be improved in Rune is how programmatic access to Rune values is done. Currently it requires a number of stages of checks and conversions with errors:

let value = // value from vm call
let field = value.into_object()?.borrow_ref()?.get("field").ok_or_else(|| MissingField)?;

This could be improved by defining structs as value converters for a more convenient API on Value which perform the same kind of runtime checks.

use runestick::{OwnedMut, FromValue};

#[derive(FromValue)]
struct Object {
    pub field: OwnedMut<String>,
}

let value = // value from vm call
let object: Object = Object::from_value(&value)?;
object.field.clear();
shekohex commented 4 years ago

So, what I understand from what you said that: the state (Data) is separated from the VM (Code) which means that we could recompile the code and use the same old state to continue working on the same values.

I'd love it if someone could link the source code. Here is the example code for the Pong game: https://github.com/mun-lang/example-rs/blob/master/examples/pong.rs

What we could do better too, we could try to reuse the old compiled bytecode and patch only the changes that happened in the source-code, for example, if we have a file with only three functions and we compiled that for the first time, the compiler will compile all the 3 functions .. and after a change to only one of these functions the compiler could only detect that change and compile only that one function and patch up the original bytecode.

That's one option, another option would be we have two modes for the compiler a JIT Mode and AOT Mode, JIT Mode would be used while development so no bytecode needs to be emitted to a file and skip all of the optimizations so the compile-time would be minimum as possible, and for the AOT Mode, we do all the heavy work.

What if we could combine those both options :)

axyz commented 5 months ago

Sorry to resurrect an old issue, was wondering if there was any update around this topic. I am trying to decide between Rune, Rhai, or Mun (so far) for some small experiments, both Rhai and Mun seems to have documentation for hot reloading scenarios. Couldn't find any newer reference to the topic here and was wondering if the idea was (temporarily?) abandoned due to technical complexity, or if it is planned, or already possible but undocumented.

Also what does exactly mean not to have "hot reloading" in this context. Would it still be possible to watch for file changes and re evaluate single scripts without restarting a program? My assumption is that proper hot reloading would also allow to keep the internal state of a given script changes, so it wouldn't be a problem if the scripts only have side effects on the host, but not on the script itself?

udoprog commented 5 months ago

Scripts in Rune does not normally have any state, you have to manage state yourself through parameters you pass in. Hot reloading then is just replacing the script at runtime which is fully supported.

For reference, this is how I store state in OxidizeBot.

Any native functions you register might or might not be stateful. That's up to you.

axyz commented 5 months ago

makes sense. Maybe would be good to add a hot reloading example in the book, ideally also suggesting what watcher to use and how with a simple use case, and close this issue; otherwise from a (probably too superficial) look, is hard to tell if it's possible or not when comparing with the alternatives.

Rhai also mentions ways to hot reload specific functions instead of whole scripts, not sure if that would be possible as well?

udoprog commented 5 months ago

True, since Rune doesn't have state, this feature request doesn't really make much sense. I'm closing it for now. If someone does want to build an example, feel free to base it off the code I have in OxidizeBot.