Polymorph VM Introduction
Jakob Jenkov |
Polymorph VM is a virtual machine designed to be embedded into Java applications to make your applications or services somewhat scriptable from the outside. This turns your application or services into a "platform" - thereby enabling the outside world to interact with your application programmatically. Programmatic interaction with your app makes interaction more versatile, more flexible and smarter in general than manual interaction, fixed message formats, configuration files etc.
100% Sandboxed - Except For Functions Plugged In by You
The Polymorph VM is 100% sandboxed - except for the plugin functions you decide to plugin to the VM before having it execute a script. If you plugin no functions - the scripts cannot reach anything outside the VM. There is no built-in access to the local file system, network, OS or the Java class hierarchy.
The 100% sandboxing makes sure you get the maximum control over security when executing scripts inside your applications.
Plugin Functions
Executing a script with absolutely no access to any resources inside your application is rarely useful. Normally you will want the the scripts to have access to some functionality inside your application or service.
To make functionality inside your application available to a script you plugin one or more functions (implemented in Java) that the scripts can call.
Use Cases
Polymorph VM is primarily designed for use cases where it can be beneficial to allow some level of scripting of an application or service from the outside. The primary use cases on my mind when I designed Polymorph VM were:
- Using scripts instead of configuration files for desktop applications or services.
- Using scripts as a macro language.
- Enabling clients to send scripts to services instead of having fixed "messages" or "functions" supported by the service.
I will elaborate a bit more on these use cases in the following sections.
Scripts Instead of Configuration Files
Imagine being able to configure a desktop application or service via a script instead of via a declarative configuration file format (such as YAML, JSON, property files etc.). A script would enable more flexible decision making during configuration - allow for looping, conditional configurations, function calls etc. All of this could be supported via traditional configuration file formats - but are more easily supported via a scripting language.
Scripts as Macro Language
Some desktop applications have macro languages that can be used to extend their functionality, typically by grouping a set of actions inside the application into commands which can be repeated on demand. By plugging in a Polymorph VM you can get a macro language for free, and plugin the functionality you want to expose to the macro language via plugin functions.
Scripts Instead of Messages
Imagine being able to send a script to a service for execution instead of a fixed message. A script could have access to a set of functions exposed by your service - enabling the script to make intelligent decisions about what functions to call - without having to make a round-trip back to the client between each decision.
Non-Design Goals
Polymorph VM is NOT intended to be a general purpose programming platform. The goal is only to run smaller scripts inside an existing application. Therefore the language is rather simple, and not optimized for performance. Heavy calculations or special application or platform functionality are expected to be performed via calls to plugin functions.
Design Goals
The Polymorph VM has the been designed with the following design goals in mind:
- Small scripting language
- High expressiveness
- Streamed execution
- Incremental execution for single-threaded concurrency
I will elaborate a bit more on these design goals in the following sections:
Small Language
Since the goal of Polymorph VM is not to create a general-purpose application platform - there is no reason to implement a highly advanced scripting language. Quite the opposite, in fact. The smaller the language is, the easier it is to learn. Of course, there is a limit to how small the language can be and still be reasonably versatile - but I am trying to keep the language small.
High Expressiveness
Since the target use cases for the scripting language for the Polymorph VM is configuration or queries sent over the network to a service, it is beneficial that the language is highly expressive. By highly expressive I mean a language that is able to express a lot of meaning in a concise syntax.
I have two syntax suggestions that build method-chaining (fluid style APIs) directly into the language itself. These syntax suggestions will make it easier to express more complex object graphs than using normal Java. Object graphs are often used in configuring APIs or applications, and to express complex commands or queries. Hence, concise expression of object graphs is useful for the target use cases of this language.
Streamed Execution
The scripting language for Polymorph VM is designed for streamed execution - meaning that it must be possible to start executing the script before the full script has been loaded / downloaded / received. This also means that the VM cannot rely on all functions or types used by a script being available in the local file system, such as is the case with other languages. For a script to be able to use a function or type, it must have been defined in-stream previously.
Streamed execution is useful when using the scripting language to carry dialog between a client and a server.
Incremental Execution
The scripting language (its bincode at least) is designed for incremental execution. This means, that instructions must be executable one instruction increment at a time. For instructions that are atomic, this is not hard to achieve, but for instructions that can have nested instructions, such as if-statements, loops and function calls, this is harder. However, I believe I have found a workable design for the bincode and VM that supports this.
Incremental execution makes it possible to have multiple VMs executing scripts concurrently within a single thread. The thread can switch between executing an increment within each of the VMs in round-robin fashions - just as if each VM was executed by its own thread. Thus, incremental execution enables single-threaded concurrency (executing multiple tasks seemingly at the same time within the same thread).
Single-threaded concurrency is useful inside servers and routers using a single-threaded / same-threaded design - which the Polymorph Fabric node is intended to use.
Tweet | |
Jakob Jenkov |