Ferite
A small, threadsafe, BSD-licensed scripting engine written in C, born out of one developer's frustration at embedding Perl, and remembered for its blocks-passed-to-functions syntax and its monitor/handle error handling.
Created by Chris Ross
Ferite is a small object-oriented scripting language and engine, written in C, whose reason for existing was never the language itself. It was written to be embedded: dropped into a C or Objective-C application so that the application could be scripted, configured and extended without shipping a second runtime the size of Perl or Python. The design goals its own manual lists are, in order, “lightweight - small memory and CPU footprint, fast, threadsafe, and straight forward” for both the host application’s programmer and the script writer.
It is a curly-brace language, and deliberately so. Its author described the influences precisely: Java for objects, C and PHP for functions, Scheme for closures, Ruby for block calling, and C++ for namespaces. What came out the other side reads like PHP that grew up around a proper object model, with a handful of ideas - monitor/handle/else error blocks, functions that accept a caller-supplied block via using, and deliver()/recipient() for passing those blocks onward - that are genuinely its own.
Ferite was substantially the work of one person, Chris Ross (who signed his commits and mail as boris or ctr), with a handful of regular contributors. It was never adopted widely enough to become a household name, but it did something most hobby languages never manage: it shipped in Debian and FreeBSD for years, and a real commercial product was built on top of it.
History & Origins
Started because embedding Perl was painful
The project’s own about page traces the beginning to Summer 2000, after around two years of the author playing with the idea, and is blunt about the trigger: frustration at trying to embed Perl inside an application. Anyone who has read perlembed will recognise the complaint. The ferite project was registered on SourceForge on 19 July 2000, under the categories code generators, compilers and interpreters, with C and Objective-C listed as its implementation languages.
The engine is a compiler and a bytecode virtual machine, both written in portable C, with an explicit C API for embedding and for writing native modules. Documentation copyright notices in the manual reach back to 1999, and the source licence header covers 1999 to 2005 - so the earliest code predates the public project by a year or so.
2001 to 2002: escaping into the distributions
Public releases were circulating by 2001: the FreeBSD ports tree gained lang/ferite on 14 October 2001, and an intent-to-package bug was filed against Debian on 9 January 2002 for version 0.99.4, naming Chris Ross as upstream and the licence as BSD. The description in that bug is the one that followed ferite around for years afterwards - “strong similiarities to perl, python, C, Java and pascal, while being both lightweight, modular, and embeddable”.
The 0.99.x numbering is worth noting, because it lasted a long time. The website’s front page carried the line “We are currently marching towards a 1.0 release - this has only taken use since Summer 2000 to get here so far”, and the stable version was reportedly still 0.99.6 as late as 2004. Ferite spent roughly four years in the run-up to 1.0, adding features that many languages would have shipped a major version for.
The credited team
The project’s team page names, besides Ross, Evan Webb (whose array implementation replaced the original), Stephan Engström (the Sys module and engine optimisation work), and Alex Holden (Sys module and fixes), with acknowledgements to Blake Watters for converting the documentation to SGML, Pete Vassof for the String module, and others for IPC work and general help.
Design Philosophy
Embeddable first, standalone second
Ferite’s pitch is that the engine is a library. The host application creates a script engine, exposes native functions and classes to it through the C API, and runs scripts; the ferite command-line interpreter is essentially a thin standalone user of that same API. The dependency list stayed correspondingly small - the FreeBSD port needed only libpcre and libxml2 - and threadsafety was a stated goal from early on, at a time when many scripting engines still had a global interpreter lock or worse.
The build also ships a documentation generator (feritedoc), a module scaffolding tool (generate-module), and farm, the project’s tooling for installing modules outside the engine’s own prefix.
Declared types, checked at runtime
Ferite variables are declared with a type - the manual lists number, string, array, object and void - but the checking happens when the assignment executes, not at compile time. The engine’s own test suite makes the behaviour explicit: assigning a string to a number raises a catchable runtime error, while assigning a string to a string does not.
number blarg = 10;
monitor {
blarg = "blarg";
} handle {
Console.println( "Failed: " + err.str + " (" + err.num + ")" );
} else {
Console.println( "This branch does not run" );
}
That monitor/handle/else construct is ferite’s exception handling, and the else clause - a block that runs only when the monitored code raised nothing - is an unusual touch. Earlier versions spelled the same idea iferr/fix/else, and the iferr form survived into the 1.0 release notes, where a fix for iferr blocks inside loops is listed as one of the last changes before 1.0 final.
Key Features
Blocks passed to functions
The feature ferite is most worth remembering for arrived with the 1.0 release candidates: any function can be handed a block by the caller with the using keyword, and that block is a closure. It is the Ruby idea, expressed in curly-brace syntax:
uses "console", "array";
Array.each( [ 1, 2, 3 ] ) using ( value ) {
Console.println( value * 5 );
};
Inside the called function, the block is reached through deliver(), which invokes it, and recipient(), which returns it as an object so it can be stored, invoked repeatedly, or forwarded to a third function:
function threeTimes() {
deliver();
deliver();
deliver();
}
function passOnToThreeTimes() {
threeTimes() using recipient();
}
threeTimes() using {
Console.println( "Hello World" );
};
Standalone closures use the closure keyword and capture their enclosing scope, and are called through invoke():
function nTimes( void thing ) {
return closure ( n ) {
return thing * n;
};
}
object o = nTimes( 23 );
Console.println( "${o.invoke(3)}" );
Strings interpolate with $name and ${expression}, in the Perl and PHP tradition.
Objects, namespaces, and modifying both
Classes support inheritance with extends, abstract and final modifiers, static members, static constructors, and access control - variables private and methods public by default, per the February 2003 announcement that introduced private, protected and public. From 1.0, constructors are named constructor rather than sharing the class name.
Namespaces come from C++ and nest, with a leading dot addressing the current namespace and super the enclosing one:
namespace blah
{
number i;
function blit( string blip ) {
Console.println( "in blit: " + blip );
blah.i = 10;
}
namespace inside
{
function insidei() {
Console.println( "blah.inside.insidei()" );
}
function testi() {
.insidei();
super.blit( 'foo' );
}
}
}
The manual documents modifying existing classes and namespaces after the fact - reopening them to add members - which is closer to Ruby than to C++ or Java.
Regular expressions, moved out of the language
Early ferite had Perl-style regular expressions baked into the grammar, complete with backtick syntax. The 1.0 release notes record their removal from the language proper and their relocation into a module named regexp, on the grounds that a module was “more ferite esque”. The module keeps the block-passing style, so matching and replacing can both take a block:
uses "console", "regexp";
object o = new Regexp( "([0-9]+)" );
array a = o.matchAll( "123 456 789 345" ) using ( match ) {
Console.println( "Got match: '${match.match()}' in range '${match.span()}'" );
};
string replaced = o.replaceAll( "1234 is the 123456" ) using ( match ) {
return "${match.match()}.feriteRocks";
};
Other notable capabilities
- Parameter overloading - several functions of the same name distinguished by declared parameter types, added in the January 2003 release.
- Call by reference, written
function f( number &b ), added in the 1.0 series. - Variable argument lists, reached through
arguments()(renamed fromgetArgs()in 1.0). - Reflection, including runtime inspection of objects and functions and the ability to trace a variable’s modification.
- Serialisation, with both a native and an XML form, plus a small pure-ferite remote method invocation framework.
- Optional Boehm garbage collection - from 1.1.12 in February 2009, ferite would detect and use
libgcby default.
Platform Support
The project’s about page lists the platforms it ran on as Linux, Solaris, Mac OS X, Cygwin and FreeBSD, and the SourceForge project entry records BSD, Linux, Mac and Solaris. Windows was a recurring aspiration rather than a supported target: the changelog contains entries about Windows fixes attempted ahead of the 1.0 release, and contemporary discussion noted the absence of a native Win32 port, with Cygwin as the available route.
Evolution
The version history divides cleanly into three phases.
| Phase | Roughly | Character |
|---|---|---|
| 0.99.x | 2001 - 2004 | Rapid feature growth under a pre-1.0 label: static members, namespaces extending namespaces, variable argument lists, include(), array initialisers, switch, an array subsystem rewrite, a new module system, foreach, ternary conditionals, access modifiers, and finally closures |
| 1.0.x | 2005 | Consolidation. Rewritten manual, embedding guide and C API docs; the using block syntax and closure keyword; constructors renamed; regular expressions moved to a module; call by reference |
| 1.1.x | 2006 - 2009 | Maintenance and performance. UTF-8 string fixes, Array.append, optional libgc, a compile cache, and a stream of bug fixes, ending at 1.1.17 |
Development effectively ended with the 1.1.17 tarball of 22 October 2009. The source was moved to GitHub in May 2010, with the module collection following the next month, and the last commits to the core engine were made in July 2011. The development tree there still carries the version number 1.1.19, a release that never shipped.
Current Relevance
Ferite is dormant, and has been for well over a decade. The clearest marker is FreeBSD’s removal of lang/ferite on 31 October 2024 with the note that it was “Abandonware and outdated, last release in 2009 (current version in 2005)” - the port had outlived upstream by fifteen years.
The one place ferite kept working for real money was Cention AB. Its GitHub organisation holds a maintained fork of the engine (ferite-1.1.18), an Apache module, a web framework, and modules written specifically for the Cention Suite’s email, export and reporting features - several with commits into the mid-to-late 2010s. Whatever else can be said about ferite’s reach, a commercial product ran on it years after its author had moved on.
Anyone wanting to run ferite today has to build it from source: the GitHub tree still uses autotools (./configure && make && make install), and there is no official or community Docker image. Expect friction from a C codebase last touched in 2011 meeting a modern toolchain - the FreeBSD port carried a stack of local patches for exactly this reason.
Why It Matters
Ferite is a good case study in a category of language that was crowded in the early 2000s and has almost entirely disappeared: the embeddable general-purpose scripting engine. Lua won that fight decisively, and Python and later JavaScript engines took much of the rest. Ferite made a defensible bet - a fuller object model and a richer standard library than Lua, a much smaller footprint than Perl - and lost anyway, largely for reasons that had nothing to do with the language: no corporate sponsor, one primary author, and a four-year march to 1.0 during which its competitors’ ecosystems compounded.
What is worth taking from it is the syntax. Ferite put Ruby-style blocks into a C-family language, gave them a first-class calling convention (using, deliver(), recipient()), and applied that convention consistently across its own libraries - iteration, regular expression matching, string replacement - years before blocks and lambdas became standard equipment in mainstream curly-brace languages. Its monitor/handle/else construct, with an else branch for the no-error case, shares a shape with Python’s older try/except/else - a shape most C-family languages still lack.
It is also a reminder of how much a small project can produce when someone keeps at it: a bytecode VM, a threadsafe embedding API, a documentation generator, a module scaffolding tool, book-length manuals, and a couple of dozen modules - all under a BSD licence, and all still readable on GitHub.
References
- ferite.org project site (SourceForge mirror) - about page, news archive and the online manual
- darkrock/ferite on GitHub - source,
ChangeLog,RELEASE.NOTESand thescripts/testexamples - ferite on SourceForge - project registration, releases and the final 1.1.17 tarball
- Debian bug #128487 - ITP: ferite - the January 2002 intent-to-package
- FreshPorts - lang/ferite - FreeBSD port history from 2001 to its removal in 2024
- cention on GitHub - Cention AB’s ferite fork and Cention Suite modules
Timeline
Notable Uses & Legacy
Cention AB
The Swedish customer-service software company hosted one of ferite.org's official mirrors and built on the language heavily. Its GitHub organisation carries a ferite-1.1.18 fork described as the stable version of the language, an Apache module (mod_ferite), and application-specific modules for the Cention Suite covering email, exports, reports and statistics - some with commits as late as 2016 to 2019, long after upstream development had stopped.
Debian GNU/Linux
Ferite was packaged for Debian from an intent-to-package bug filed in January 2002; the archive holds source packages for 0.99.4-4 and for 1.0.0.1+rc2-1, which first appeared in March 2005.
FreeBSD ports
lang/ferite was added on 14 October 2001 and survived in the ports tree until 31 October 2024, depending only on libpcre and libxml2 - a small dependency footprint that matched the engine's embedded-first design goals.
Ferite.framework for Cocoa
An Objective-C framework for embedding the engine into Mac OS X applications, reported as work in progress in 2003. The project's SourceForge listing records Objective-C alongside C as an implementation language, and later build scripts contain explicit Mac OS X version checks.
The ferite module ecosystem
The engine's C extension API was exercised by a long list of modules maintained by Chris Ross and contributors - XML and XSLT, database access, zip, SOAP, JSON, memcached, Cairo and Pango drawing, Selenium driving, and a web framework - which together are the clearest surviving record of what people actually built with ferite.