Introduction to Monoglot

Overview

Monoglot is a platform for developing lightweight, deployable, scalable network applications in Lua. The resulting applications can be easily deployed as standalone executables, or integrated into existing executables.

Those familiar with Node.js will recognize many similarities with Monoglot, although Monoglot is much smaller and easier to use.

Those familiar with Ruby-based web environments will find Monoglot's programming model similar, but without the installation, configuration, and deployment hassles.

Technical Details

Core Components

Monoglot combines the Lua interpreter with a set of libraries that support:

Event-Driven I/O

Monoglot uses an event-driven networking model. Each instance of the Lua VM inhabits a single kernel thread, but that thread can handle many network connections. (In this respect, Monoglot is much like Node.js.)

Synchronous Programming Model

Although the underlying kernel APIs it uses are event-driven, Monoglot presents the Lua programmer with a “synchronous” or “threaded” usage model. Lua's support for coroutines is used to implement cooperative (non-preemptive) threads of execution.

This differs from Node.js and in-browser JavaScript development, in which programmers pass callbacks to functions that can trigger long-lived operations.

Zero Installation

Monoglot avoids dependencies on system configuration. A Monoglot-based project typically includes all of its dependencies in a single source tree. The application can then be deployed along with its dependencies as a single executable.

Hybrid configurations can also be employed, where some amount of the scripts are embedded in the applications while others are loaded at run time from the file system.

Benefits

Footprint

“... get a simpler language. Lua is much simpler than JS. This means you can make a simple interpreter that runs fast enough ...” — Brendan Eich, creator of JavaScript. [link]

Code Size

A smaller executable means that it can run in resource-constrained environments, leaving more room for applications and data.

A smaller source base makes it easier to fully understand Monoglot and audit the source for security issues.

The following table summarizes Monoglot and Node.js (v0.10.16).

Monoglot

Node.js

Ratio

Binary (MB)

0.25

12

48x

C/C++ sources (KLOC)

19

806

42x

C/C++ sources (KB)

479

26,770

56x

Other sources (KLOC)

10

363

38x

Other sources (KB)

249

14,308

58x

The code sizes listed above exclude tests. The binary sizes are release-mode builds on MacOS including statically linked versions of dependencies except the C and C++ standard libraries, which are not included.

It should be noted that Node.js builds in a number of libraries that may or may not be required for different applications. Monoglot includes a minimal set of libraries, and makes it easy for applications to build in only the libraries they need. Most notably, Monoglot does not yet include SSL, which would be important for most use cases.

RAM Footprint

Monoglot's tiny executable size reduces memory footprint when executing.

Also, the event-driven model can result in significantly lower resource usage than models that require a thread per connection (e.g. Python or Ruby). Each kernel thread occupies space in kernel data structures and requires memory to be allocated for stacks.

Performance

tooltree/bench compares minimalist web servers based on Monoglot and Node.js.

Platform

Transactions per second

Monoglot

18,239

Node.js

13,380

LuaJIT offers the possibility of significantly boosting Monoglot performance on supported acrhitectures (ARM, x86 and x86-64). Monoglot currently uses the Lua.org interpreter, which supports many more architectures than LuaJIT or Node.js.

The performance difference may be more pronounced on a single-core processor or in a high-load multi-process deployment, since Node.js appears to make more use of other threads, resulting in higher total CPU loading than Monoglot in the above test scenario.

Synchronous Coding Style

Monoglot's synchronous/threaded programming model affords a number of benefits over the “callback-based” or “asynchronous” style of programming used in Node.js. (We have experienced these firsthand while developing Node.js-based software.)

The most obvious drawback to asynchronous programming is that it does not compose well with language features. The programmer cannot make use of for and while loops, recursive function calls, and exception handling, when these constructs would have to wrap long-lived operations. The programmer is forced into a more primitive style of programming, resulting in tedious, difficult to read code.

The lack of composability with exception handling, in particular, poses a challenge for robustness. In Node.js, for example, any exception occurring in any callback can leave the server in a corrupted state if it is not caught. Exhaustively guarding against this possibility by trapping all exceptions and cascading them appropriately is an onerous burden.

Another problem relates to the difficulty of cancellation of operations. In many environments, including Node.js, cancellation of pending operations is not always possible. When it is, the mechanisms are ad hoc — each scheduling API provides its own corresponding cancellation API.

Lua

Lua is a more powerful language than JavaScript, yet easier to learn.

Aside from coroutines, which allow the scalable implementation of threads, Lua offers many other benefits over JavaScript:

Portability

Monoglot currently supports Linux, MacOS, and Android.

Windows support could be added without much difficulty.

Ease of Deployment

The Zero Installation approach allows easy deployment of an application along with its dependencies. This can be contrasted with packages that have uncontrolled external dependencies, expecting them to be installed on the host, which can experience the following problems:

Potential Applications