Returning instances from Kotlin scripts, storing them in a map, then executing methods on those instances to front-load the performance cost?

Hello everyone, this is my first post here so be gentle :slight_smile:

This isn’t a request for support as such, as I have something that seems really great working. This is more of a… journey of further understanding.

I am a game developer leveraging Kotlin heavily in my server implementation and have just started exploring using Kotlin scripts as my primary scripting tool so I can add unique behaviours to various stuff in the game without hard coding things all over the place.

Anyway, I digress…

With my implementation I essentially scan a series of directories for kts files. Each of these kts files defines an implementation of an abstract class from my main codebase with an “execute” method that I pass a reference to a sort of… engine API class so the scripts can call in and do things, then simply creates an instance of that implementation.

My main codebase then essentially reads each of these scripts at startup into instances of the abstract class that they all extend, and files them away in a map so I can find and execute them easily at runtime.

After some testing it seems to be the case that working in this way allows me to pay the performance cost of script execution up front at startup, then essentially take no performance hit at runtime as I am just hitting my instances execute method.

It also seems that working in this way allows my scripts to interact fully with all aspects of my compiled codebase as if they were themselves compiled with it in the first place. Assumedly this is due to the returned instances then being executed by compiled code so they share the classpath, stack, etc, which seems both brilliant and terrifying at the same time.

I am new to leveraging scripting in any capacity, so I have two questions I would very much appreciate someone experienced to weigh in on:

  1. Am I correct in my assertion that once I have hold of my implementation instance from the kts file, I have paid the performance penalty for running that script and calling methods on it really is the same (performance wise) as if that had been compiled code?
  2. If this is the case, is there a reason I haven’t seen this done before? Have I just been living under a rock? I spent quite a bit of time trying to figure out how to use Kotlin scripting to extend my game engine but resources online seemed sparse and complicated, with many warnings of performance and no real case studies of claims of others achieving the same thing… however if the ability to modify the script at runtime isn’t necessary then this pattern I’ve conjured up seems to be the bees knees, no?

Cheers everyone,
Liam

Your script evaluation consists of two phases: script parsing and compilation and evaluation itself. If you cache the script instance, you won’t have to pay compilation fee in secondary invocations. This is exactly what GitHub - kscripting/kscript: Scripting enhancements for Kotlin does.

1 Like