Est. 1997 Intermediate

elastiC

A portable, object-oriented scripting language from the late 1990s that wraps a Smalltalk object model and Scheme-style closures in C syntax, compiles to portable bytecode, and was built from the start to be embedded in and extended from C programs.

Created by Marco Pantaleoni

Paradigm Multi-paradigm: object-oriented with a Smalltalk-style object model and meta-programming, functional programming with first-class functions and lexically scoped closures, and ordinary C-like imperative and procedural code
Typing Dynamic and strong - types belong to values rather than to variables, and there are no type declarations
First Appeared Development dates to 1997 - the earliest source files in the distribution carry creation dates of March 1997 and the copyright notices begin at 1997 - with public releases and a documented ChangeLog starting around late 1999
Latest Version 0.0.35, whose files are dated November 2001. The project never reached a 1.0 release

elastiC is a portable, object-oriented, bytecode-compiled scripting language written by the Italian developer Marco Pantaleoni, with development dating to 1997 and public releases running from around 1999 to 2001. Its pitch was straightforward and, for its moment, ambitious: take C’s syntax - the syntax nearly every working programmer already knew - and put behind it a Smalltalk object model, Scheme’s lexical closures, Python’s convenience types, and a real garbage collector. The project’s own summary of its lineage is unusually candid about this: elastiC “has been strongly influenced by C, Smalltalk, Scheme and Python and tries to merge the best characteristics of all these languages, while still coherently maintaining its unique personality.”

It is a dormant language today. The last release, 0.0.35, has files dated November 2001; the version number never reached 1.0; the CVS and Subversion repositories were hosted on BerliOS, a service that no longer exists. What survives is a source tarball, a set of manual pages, and a design that is worth reading precisely because so many of its bets were the right ones - made by someone working essentially alone, at the same time as much better-resourced projects were making them.

History and Origins

elastiC’s earliest source files are dated March 1997. The scanner, the parser, the hash functions and the memory allocator all carry creation dates from that spring; the garbage collector followed on 9 December 1998. The copyright notices across the distribution begin at 1997, which is the basis for dating the language to that year even though nothing was publicly released under a tracked version number until later.

The public record starts on 4 November 1999, the first entry in the ChangeLog, and it reads like exactly what it was - a personal project being turned into a distributable one. Man pages and examples were added. Closure creation bugs were fixed. Copy-construction support was added across all types. Within weeks the build was moved to GNU automake and libtool, an elastic-config tool was added for downstream module authors, library versioning went into the API, and the ec, ecc and ecdump utilities grew -h and -v options - the last of these at the suggestion of David N. Welton, who is also credited in the acknowledgements for documentation work.

The releases that followed are small-numbered and feature-dense. Version 0.0.4 brought the regular-expression module built on PCRE 2.08 and the string library that made the language practical. Version 0.0.6 added labels and goto, with the author’s terse justification recorded in the release notes: “Sorry, I need it to implement lex & yacc in/for elastiC.” Versions 0.0.30 and 0.0.31 added multiple simultaneous assignment and then reworked its syntax from parentheses to brackets to resolve a grammar conflict. Version 0.0.33, in late 2001, added %-based string formatting and default parameter values.

Then it stopped. Versions 0.0.34 and 0.0.35 are portability fixes - making the code compile under gcc 2.96 and 3.x and bringing it into line with strict ANSI C - and 0.0.35, dated 21 November 2001, is where the download page still ends. Two later dated items appear on the site: a December 2001 nomination in the Best Italian Free Software Project Award, and an October 2004 listing among the projects eligible for IBM’s Linux on POWER Open Source Developer Contest. After that, nothing.

Design Philosophy

Familiar syntax, unfamiliar semantics

The central design decision is a trade that many languages have since repeated: adopt the surface most programmers already know, and spend the novelty budget entirely on semantics. An elastiC program looks like C. It has braces, semicolons, for loops, // and /* */ comments, and a small reserved-word list that includes break, continue, if, else, while, do, for, return and goto.

Underneath, almost nothing about it is C. Variables are untyped containers; types belong to values. Memory is managed by a tracing collector. Functions are first-class values that can be nested, passed and closed over. Objects respond to messages in the Smalltalk sense. The claim in the manual is that the C-like syntax makes the language “very easy to learn” while its powerful features remain available - the same argument made for JavaScript, which had taken the same C-surface-with-closures approach two years earlier.

Everything in a package

Every elastiC program lives in a module, declared at the top of the file, and every module can import others. Top-level names are explicitly public or private (with local as a synonym for private), and that applies to functions and classes as much as to variables, because functions and classes are values. Namespaces are hierarchical, and library calls are qualified: basic.print, string.split, array.push. For a scripting language of the late 1990s, this was a notably disciplined stance - Python’s module system was comparable, but plenty of contemporaries had a single flat global namespace and a naming convention.

The canonical first program shows the whole structure:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
package hello;

// Import the `basic' package
import basic;

// Define a simple function
function hello()
{
    // Print hello world
    basic.print( "*** Hello world! ***\n" );
}

// Here we start to execute package code
hello();

Running ec hello.ec compiles and executes it in one step; ecc hello.ec compiles it to a .ecc bytecode file that ec hello then runs.

Compile once, run anywhere the interpreter builds

elastiC is a bytecode language. The ecc compiler produces portable bytecode object files, the ec interpreter executes them, and ecdump disassembles them. The whole system is written in C with no dependency on a larger runtime - the stated design goals include a small footprint and embeddability in C programs, which is the profile of a language intended to be a component rather than a platform. Bytecode objects carry debug data, including line numbers, which the 0.0.31 release notes point out lets line information survive in optimized builds “without any performance degradation.”

On portability: the distribution’s INSTALL file is honest about what was actually verified. It states that elastiC “has been tested only on linux with glibc, but it should compile fine (or with modest adjustments) on all modern unix variants.” Precompiled Win32 executables were offered on the download page, but only for the older 0.0.15, and AIX native-compiler support appears in the acknowledgements as a contribution. Anything beyond Linux/glibc should be treated as plausible rather than documented.

Key Features

The Smalltalk object model

Classes are declared with class ... extends, instance variables with local, class variables with static, and methods with method. Message sends use bracket syntax borrowed directly from Smalltalk, including keyword messages - a genuinely unusual thing to find grafted onto C syntax:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package shapes;

import basic;

public class Shape extends basic.Object
{
    local name;
    local color;

    // a method with keywords
    method setName: shapeName andColor: shapeColor
    {
        name  = shapeName;
        color = shapeColor;
    }

    method print()
    {
        basic.print( [[self isA] name],   "\n",
                     "   name : ", name,  "\n",
                     "   area : ", [self getArea], "\n" );
    }
}

public class Rectangle extends Shape
{
    local w, h;

    method init( name, color, width, height )
    {
        [super setName: name andColor: color];
        w = width;
        h = height;
    }

    method getArea()
    {
        return w * h;
    }
}

The Smalltalk inheritance extends to reflection: basic.Object provides doesUnderstand, and the basic.send and basic.sendwith functions dispatch a message to a receiver given the method symbol and its arguments - either directly or packed in an array. That is a message-passing meta-object protocol, not merely method-call syntax.

Closures and functional programming

Functions are first class and lexically scoped, and anonymous functions can be written inline and capture their enclosing environment. The distribution’s closure.ec example is a compact demonstration, notable for shipping alongside a closure.scm that does the same thing in Scheme:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// a function mapping an operation element-wise over a sequence
function map( sequence, oper )
{
    local result = #[];
    local el;
    for (el in sequence)
        array.push( result, oper( el ) );
    return result;
}

function pow( sequence, y )
{
    // We pass a closure referencing our argument y as the operation
    return map( sequence,
                function( x )
                {
                    return x ** y;
                } );
}

In 1999, a working closure in a C-syntax language was not a given. C++ would not get lambdas until C++11; Java would not get them until Java 8 in 2014.

Types and literals

TypeLiteral syntaxNotes
Integer12345, 0x3039, 030071Decimal, hex and octal, as in C
Float123.45, 1.2345e2
Character'a', '\n'C escape sequences
Boolean@true, @false@nil, @false and integer 0 are the only false values
Null@nilTypeless, but a first-class value
String"abc"Mutable and growable - assigning past the end expands the string
Symbol#aSymbol, 'aSymbolSmalltalk-style # or LISP-style '
Array#[1, 'a', 20.5, "ABCD"]Dynamic; supports negative indexing, so a[-1] is the last element
Hash%["color", "orange", "weight", 12]Any value can be a key, including arrays and functions

Symbols get an explicit performance rationale in the documentation, and it is a design argument rather than a benchmark: symbols are translated to integers at compile time and handled as integers thereafter, so they cost less memory than strings and compare faster, which is why they - not strings - are the recommended representation for symbolic constants and enumeration-like values. No published benchmark figures accompany the claim, and the “very fast” garbage collector in the feature list is likewise an assertion by the author rather than a measured result against a named baseline.

Hash keys really are unrestricted. The manual’s own example uses an array as a key mapping to another array, which requires the runtime to hash structured values - and the 0.0.31 release notes record a corresponding improvement to floating-point hashing.

Exceptions

Exception handling is described as pervasive, and the syntax is try / catch / throw, with exception classes participating in the ordinary class hierarchy:

1
2
3
4
5
try {
    throw [IOError new: "Test exception. Don't worry !"];
} catch (IOError e) {
    [e shout];
}

Built-in errors are classes too - basic.UnknownMethodError is catchable, and the caught object can be queried for the method and target involved. This is more structured error handling than several better-known scripting languages of the same era shipped with.

Extending and embedding

elastiC’s C interface goes in both directions. New functions, types, classes, methods and whole packages can be added in C; the interpreter can equally be embedded in a larger C program as a library. The ecosystem around this was the project’s most active area: an FFI module built on libffi for calling C functions without writing glue, a SWIG target for generating bindings automatically, a skeleton module template for dynamically loadable C extensions, and modules for GTK+/GDK and networking.

Evolution

The version history is short and, read in order, shows a language converging on the same set of conveniences its contemporaries were adopting:

  • 0.0.3 - switch to automake/libtool, version numbering scheme, elastic-config
  • 0.0.4 - the re module on PCRE 2.08, and the working string library
  • 0.0.5-0.0.6 - OOP bug fixes, varargs for keyword methods, doesUnderstand, basic.send, and goto
  • 0.0.30-0.0.31 - multiple simultaneous assignment, then sequence assignment to multiple lvalues; debug info moved into bytecode objects
  • 0.0.32 - basic.printf, Python-style named conversion specifiers such as %(city)s, improved regression testing
  • 0.0.33 - % string formatting operator, default parameter values evaluated at call time
  • 0.0.34-0.0.35 - ANSI C conformance and gcc 3.x compatibility

The tell is in the last two. A project whose final releases are compiler-compatibility fixes is a project being maintained rather than developed, and after November 2001 even that maintenance stops appearing in the record. The documentation shows the same seam from the other side: the quick reference’s table of contents lists sections for exceptions, closures and most of the standard library that were never filled in.

Current Relevance

elastiC is dormant, and the practical situation is bleaker than that word usually implies. There is no package in current Linux distributions, no Docker image, no active repository, and no maintained community. The infrastructure the project depended on has been dismantled: BerliOS, which hosted the CVS, SVN and bug tracking, has been gone for over a decade, and SunWorld, which carried its one mainstream press mention, is long defunct. The site itself is a frameset from the era, and its HTTPS certificate no longer validates.

Building it today is a source-archaeology exercise rather than an installation. The 0.0.35 tarball is still downloadable, and it is a conventional GNU autotools package - ./configure && make - but the toolchain assumptions are from 2001. It was last verified against gcc 3.x; modern compilers default to language and warning settings that did not exist when it was written, and the bundled libtool and libltdl are of the same vintage. Anyone attempting a build should expect to patch.

The name is also a practical problem. Searching for “elastiC” today returns Elasticsearch, the Elastic License and Elastic N.V. - the company incorporated in 2012 as Elasticsearch BV, which has nothing to do with the language. This is a small but real reason the project has become hard to find even when someone is looking for it.

Why It Matters

elastiC’s interest is not in what it achieved - by any adoption measure, very little - but in what it demonstrates about a specific moment in language design.

It shows the C-syntax-with-modern-semantics bet being made early, and correctly. The proposition that a language could look like C while providing closures, garbage collection and message-passing objects was not obviously right in 1997. JavaScript had made the same bet in 1995, but it took years for the industry to accept it: C++ and Java only retrofitted lambdas onto themselves in 2011 (C++11) and 2014 (Java 8), a decade or more after elastiC - a one-person project - had shipped them.

It shows how thoroughly the embeddable-scripting niche consolidated. elastiC’s stated goals - small footprint, embeddable in C, extensible from C, portable bytecode, suitable for embedded systems - describe the same target Lua hit and holds to this day. The technical case for elastiC was reasonable and it lost anyway, which is a useful corrective to the idea that language adoption tracks language quality. What Lua had that elastiC did not was institutional continuity, a research group behind it, and enough early adopters to make the next adopter’s decision easy.

It shows how much of a language is infrastructure rather than design. Everything that made elastiC hard to sustain is external to the language: a single maintainer, a bespoke license nobody else used, hosting that outlived neither the decade nor the project, documentation sections that were outlined and never written, and a version number that never crossed the psychological threshold of 1.0. None of these are flaws in the semantics. All of them were fatal.

For a reader interested in language implementation, the source remains genuinely instructive. It is a complete, self-contained, readable C implementation of a dynamic language: a lex/yacc front end, a bytecode compiler, an interpreter loop, a tracing garbage collector over its own object heap, a symbol table, an extension API and an embedding API - the entire stack, at a scale a single person can hold in their head. That was rarer in 1997 than it is now, and it is still a reasonable thing to read.

Timeline

1997
Marco Pantaleoni begins work on elastiC. The oldest files in the released source tree - the scanner and parser, the hashing and memory routines - carry creation dates from March, April, May and October 1997, and copyright notices in the distribution start at 1997
1998
The garbage collector is written: src/gc.c in the released distribution records a creation date of 9 December 1998, giving elastiC the tracing collector that its documentation would later advertise as one of its defining features
1999
The elastiC License version 1.0 is issued, carrying a 1999 copyright. It is a short, permissive, BSD-style license that explicitly allows commercial use, with attribution and notice-retention requirements rather than copyleft ones
1999
The public ChangeLog opens on 4 November 1999 with man pages, examples and closure bug fixes, and the project switches to GNU automake and libtool a few weeks later. The elastic-config tool, library versioning and the -v and -h options for the ec, ecc and ecdump utilities all arrive in November 1999
1999
Release 0.0.4 adds the re regular-expression module, built on PCRE 2.08, along with string.split, string.join, string.trim and friends - the practical standard-library work that turns the language into something usable for scripting
2000
Per the project's own web site, elastiC is mentioned in the August 2000 'Regular Expressions' column in SunWorld - one of the few pieces of mainstream press coverage the language received
2001
Release 0.0.31 implements sequence assignment to multiple lvalues and moves debug line-number data into bytecode objects, so line information survives optimized builds without a dedicated bytecode instruction
2001
Release 0.0.33 (work dated November 2001) adds Python-influenced features: printf-style string formatting with the % operator, and default values for function and method parameters, reportedly evaluated at call time inside the function scope
2001
Releases 0.0.34 and 0.0.35 are portability work - making the code build cleanly under gcc 2.96 and 3.x and bringing it closer to strict ANSI C. The files in the 0.0.35 tarball are dated 21 November 2001, and it remains the last release on the download page
2001
Per the project's web site, elastiC receives a nomination in the Best Italian Free Software Project Award in December 2001
2004
Per the project's web site, elastiC is listed in October 2004 among the projects eligible for the IBM-sponsored Linux on POWER Open Source Developer Contest - the last dated announcement on the site

Notable Uses & Legacy

Embedding elastiC as a C application's scripting layer

The primary use case the language was designed for. elastiC ships as a C library with an embedding API, and the project distributed a dedicated example package (embed-0.1) showing how to host the interpreter inside a C program. The documentation repeatedly emphasises the small footprint and suitability for embedded systems, which is the same niche Lua and Tcl occupied.

GTK+ and GDK bindings

The project distributed a gtk module (0.5) giving elastiC scripts access to GDK and GTK+, making it possible to write graphical applications for the X11 desktop of the period in the language rather than in C.

SWIG binding generation

SWIG-elastiC (0.3) added an elastiC target to SWIG 1.1p5, so that bindings for existing C libraries could be generated automatically rather than written by hand against the extension API. Being a SWIG target was, at the time, a meaningful marker that a scripting language expected to be glued to C code.

Networking with the inet module

The inet module (0.4) provided sockets and network access, including HTTP retrieval via a geturl function and network resources reachable through the ordinary file module - the plumbing needed for elastiC to be used for practical scripting rather than as a language demonstration.

Parser generation with byacc-ec

byacc-ec was a modified Berkeley Yacc that could emit object-oriented parsers in elastiC as well as in C. The language's goto statement was added specifically to make lex- and yacc-style generated code expressible in elastiC, one of the clearest cases of a real application driving a language feature.

Third-party packaging and porting

The ACKNOWLEDGEMENTS file in the distribution credits contributors for a Debian package, for AIX native compiler support and for Unicode work, indicating that the language was packaged and built outside its author's own environment - though the scale of that downstream use is not documented.

Language Influence

Influenced By

Running Today

Run examples using the official Docker image:

docker pull
Last updated: