Is there a way to redefine/reload a type in chaiscript?


#1

Let’s say for example that I have a script file like this:

test.chai:

class test {
    def test() {
         print("HELO"); 
   }
};

Then In C++ I create instances of this class and save them in boxed_values and call test() every frame in runtime.

Then, Is this next use case possible in chaiscript ?

  1. Run my app.
  2. My app eval the test.chai file.
  3. My app creates instances of test script class. And call test() function.
  4. Now while my application is running i want to change and correct the print(“HELO”) to print(“HELLO”) without restarting it.

Thanks!


#2

Very interesting question / use case.

Currently if you were to do:

class test {
    def test() {
         print("HELO"); 
   }
};

// attempt to redefine the constructor
def test::test() {
  print("HELLO");
}

You would get a ‘function redefinition’ exception thrown

This was an intentional design decision however it’s certainly possible to allow you to redefine functions and throw away the previous version.

The question would be: how would this look? Do we add a “redef” keyword? Do we make this an option during the C++ call to “eval” that says something like “allow function redefinitions?”

Or perhaps we force the user to unload the existing one first?


#3

In my opinion, a redef keyword will not be useful in this case:

first test.chai:

class test {
    def test() {
         print("HELO"); 
   }
};

editted test.chai to reload:

class test {
    var speed; // redefvar speed; ?
    redef test() {
         print("HELLO"); 
         this.speed = 2;
   }
};

because we will have to change the def test() … to redef test() … And the variables of that class ? redefvar speed ? I vote no for this option.

Maybe forcing the user to unload the type and all the instances created with that type is easier? Would you be able to handle the variables of types that are getting redefined if there are instances created with the old definition?


#4

Dynamic_Object “types” are rather loose in ChaiScript. The main thing that makes the type “real” is the functions that are defined that reference it, and they look it up by name. And member data is also a function, a function that returns a value So… it should be possible to unload them.


#5

Then, I think that an option to “eval” and “use” functions or making new functions “eval_redef” / “use_redef” functions should be sufficient.

How other script languages handle this? I never used any script language to this level to know how they handle these situations but for me, those both options should be sufficient.


#6

I’m guessing it’s not possible in most scripting engines. This kind of comes to the heart of why ChaiScript is so much more flexible and not as fast as other options. We don’t ever “fix” a function call in place. We always look up to see “what’s the most appropriate overload available right now.”

I do hope to at some point make an option that will let the user specify “I know this script is fixed and I want it to be as fast as possible” so we can do a deeper level of optimization.

-Jason


#7

Then, that would be a good feature to include because that would be one of the “selling” points for this library :smiley:


#8

I think most people/tools implement what you are asking for by doing a “save state” / “restore state” pair. It doesn’t do quite the same thing, but gets you most of the way there.

ChaiScript actually does support that with the set_state and get_state methods.

I’m reluctant to actually try and support the ability to unload / reload function definitions as I feel it would limit my future ability to do optimizations.

-Jason


#9

Uhmmm I don’t see how they do it only with set_state/get_state.

For example:
A is a chai module.
B is a chai module.
D is a chai module.

C is the chai engine.
We add first A and then we save the current C state -> CAState
Then we add B and then we save the current C state -> CABState
Then we add D and then we save the current C state -> CABDState

The problem is, if I want to “unload” or “reload” B module I can’t do a “set_state” to CAState because i’m missing the D
Module

I can’t see exactly how they do it only with set/get state functions. How would you do it?

Thanks!


#10

I think I’ve just run into this issue myself. I’ve loaded a user script and my application can call a function in it. Now I want to modify that function and so reload the script. But I’m finding that my application seems to continue to call the original one, not the new one. Is there really no way to reevaluate a script so that a call to the same named function will use new script not old one?


#11

For an embedded scripting language, the inability to redefine a function makes that scripting language infeasible for many purposes. Much as I am incredibly appreciative of the work that went into this system (and I really hate to criticize stuff I’m getting for free, even constructively), the ability to redefine a function without having to restart the entire scripting environment should be an obvious requirement, not an “interesting use case”. The world is full of examples of this kind of thing — imagine if you first had to crash a NASA rocket or shutdown a nuclear sub at sea to be able to replace a bit of code in its computer!!!

"Or perhaps we force the user to unload the existing one first?"
Which user? The ‘user’ of the scripting language is generally NOT the developer of the application that embeds the scripting language. The app developer just wants to get access to functions that the ‘user’ creates and run them under certain conditions. If the user changes a function and it’s reloaded, then the new one should always be run.

Is this something that can be addressed quickly or is it a big deal to fix?


#12

The first issue that you are hitting is that if you attempt to load a script a second time the engine says “I’ve already evaluated that file once, I’m not going to do that again” this is normal for any scripting language I’ve worked with.

Changing the behavior to allow function redefinition would actually be quite simple, but is it really what we want?

ChaiScript is very unique in the world of scripting languages. Functions can be overloaded based on type and number of parameters. Virtually no other scripting language even allows function arguments to be typed.

In this regard, ChaiScript is much more like C++, which we modeled many of our decisions after.

So, currently you have two options.

  1. In your script you could assign a global variable to be your function that you want to redefine. Example:

    global exported_func = some_other_func;
    
    • or -
    global exported_func = fun() { }; // some lambda
    
  2. save_state / restore_state: if you have a stack of modules, as @roig suggests, this would probably not be the solution you’d want to use.

In my personal code, as ChaiScript stands, I would use option #1. I will have to give the situation some thought however and decide what makes sense in the long run for maintainability.

And, regarding @dhjdhj’s comment about maintaining nuclear submarines, you would probably have each loaded module in a separate ChaiScript engine instance to provide isolation, then unloading and reloading state would be easier.


#13

The REPL in Python has a ‘reload()’ function. PHP has a tool called runkit that accomplishes the same thing. GHCi (interactive Haskell) has a ‘:load’ command. Even LISP supports it. All of these things override existing functions (or modules) of the same name. More frighteningly, Javascript allows you to completely redefine a function on the fly (I’m not advocating that though :-))


#14

I thought about that but if I understand the Chai implementation, one would end up (at least in my situation) with hundreds of chai instances (using a lot of RAM) and each one would have to have all the auxiliary functionality. Further, if one of those auxiliary functions has to be changed/fixed (which is the example I ran into) then you’d have to destroy and recreate every single instance, even if most of them aren’t executing at the time. So that essentially leaves one with exactly the same problem.


#15

I can’t talk to the maintainability of Chai but the goal here is to make it easy to maintain a collection of functions developed by individual users within an application that supports scripting to enhance the functionality of the main application. Such users should be able to edit a script with an editor (either one provided by the app or a separate editor such as sublime) and then the main application should be able to just update the scripting environment with the changed function. This is the normal way that any user would work with an REPL environment, for example.


#16

Upon further discussion with @dhjdhj on another thread I’ve realized I’ve been thinking about this wrong. I might be open to an explicit reeval/reload family of functions that enable redefining of functions.


#17

I’m ready!!!

By the way, I assume that the mechanism will work for variables (indeed any identifiers) as well. If I have written

var x = 42;

somewhere and then a reloaded script has

var x = 65

that would work too, right?


#18

Hi lefticus,

I have been integrating chaiscript in my own game and I find it super easy. I think I won’t move back to anything else. The pain point I find is exactly the same described in this thread: not being able to reload.

The reason is that I run my game and I can to add/remove things in real-time as the game runs, running a script multiple times, in which case Chaiscript throws an error. For now, global trick can do it, but it would be nice to have a more general redef solution. After all, one of the main points of scripting is to be able to iterate fast and reload change things fast. I vote for this feature and namespacing (without resorting to dynamic object) as my top prios I would like to see. Just FYI. My two cents.


#19

Hey folks.
Has there been any progress on this? Quick check of docs didn’t reveal any obvious reload/re-eval stuff. Just ran into this too - was annoyed to reload prototype over and over, having to get to the state where i could test the scripted part i wanted to fiddle with. Would be nice if i could reload files to speed up script-devel. The specific case was a bunch of classes in chai that are used as blueprints for entities’ setup/behaviour. “Attribute redefined” it says.


#20

No, no work on this yet, but it does seem to be the thing people are most asking for right now.

-Jason