Saffire: december 2012 update
Tagged with:
A few months ago I started with a new programming language called Saffire, and it’s time for an update. Since then, we have merged over 100 pull requests, and the number of contributors is steadily increasing. This post is explains of the functionality we already implemented (or want to implement).
From the user perspective, Saffire will operate the same way as “git”. This means that internally, many smaller sub-programs are called from one main binary. This keeps everything nice and tight without having to worry if you installed X or Y. If you install Saffire, you get Saffire. That’s it.
Configuration
Also, another great feature we added is the configuration management. Some aspects of Saffire can be controlled by configuration settings, and we provide a simple way to edit this configuration. Either manually the configuration file with an editor, or use the “config” command from Saffire.
First of all, generating a configuration file is easy:
$saffire config generate > myconfig.ini
Secondly, inspecting values is not hard as well:
$saffire config list fastcgi fastcgi.pid.path : /var/run/saffire.pid fastcgi.log.path : /var/log/saffire/fastcgi.log fastcgi.log.level : notice fastcgi.daemonize : false fastcgi.spawn_children : 10 fastcgi.user : -1 fastcgi.group : -1 fastcgi.listen : 0.0.0.0:8080 fastcgi.listen.backlog : -1 fastcgi.listen.socket.user : nobody fastcgi.listen.socket.group : nobody fastcgi.listen.socket.mode : 0666
Also, adding or updating a setting:
$saffire config set fastcgi.daemonize true
FastCGI
As mentioned straight from the beginning, Saffire can be run through FastCGI. We provide a FastCGI server for this (again, inside the Saffire binary), but we haven’t done much work on it. Hopefully, we can find some time to get the FastCGI working properly
Repl & Lint
Other commands are the REPL and lint checker. The lint checker does exactly what it says: it can test a single Saffire binary or even a directory for syntax errors. The REPL (read/eval/print/loop) is the interactive console where you can easily run Saffire code. It’s not functional yet. Bummer…
Compilation & interpreting
This leaves our compile and execution commands. All Saffire code is actually converted in something called byte-code, which is an intermediate code. This has got a few reasons, most importantly because it speeds up execution, and we don’t need to read the actual Saffire-source over and over again. There are actually multiple steps in between: Saffire-source code will be translated to a so-called AST, that AST will converted to Saffire-assembler code and that assembler code is transformed into the bytecode.
The actual meat of Saffire are two components: the object-engine and the virtual machine. Since everything in Saffire is
an object, this needs to be a very powerful engine. We modelled a lot of our engine on the Python engine (every language
needs a base I guess), but we have some additional features we will implement (for instance, operator and method
overloading). The operator overloading is partly functional as well. Everytime you do a a = b + 1
, it will actually
call the add
-operator from object b
.
The virtual machine is one of the most important pieces of Saffire, since most of the time will be spend inside this. It basically mimics a computer on itself (hence: virtual machine) that takes care of all kind of internals in order to run the Saffire bytecode. This also means that the virtual machine in itself should be fairly, euh, stupid. There are not many sanity checks one might expect so things will be as fast as possible for instance. We assume (and have to be 100% sure) that the bytecode we run is actually sane enough so we don’t need any checks. A lot of work has to be done to squeeze every CPU-cycle possible out of this system, but for the sake of clarity (and getting stuff done), we don’t right now. Optimization is not on our todo-list at this moment.
So, what can we actually run from Saffire? A lot of things actually. The basic foundations of the language are implemented. Think assigning and fetch identifiers, scopes, while/do/if/else statements.
a = 1; while (a < 10) { a = a + 1; if (a == 5) break; }
Looks simple, but the amount of work in order to get this running is massive. Trust me :)
Classes
Since everything is an object, classes and objects are pretty important. Right now, creating classes is functional and it’s even possible to extend other classes as well. It also knows if you call static methods from an instance (which is not allowed). One of the next things is visibility, abstract classes and implementing interfaces. Calling methods also involves arguments. An argument can have a typehint (it should be a String, a Numerical etc), and it can have a default value. The system will figure out if you added the correct arguments and types, and if not, will throw an error.
class foo { public method bar(String name = "saffire!", Numerical a = 5) { for (i=0; i<=a; i++) io.print("hello", name, "\n"); } } tmp = foo.new(); tmp.bar("world", 1); // prints hello worl 1 time tmp.bar("world"); // prints hello world, 5 times tmp.bar(); // prints hello Saffire, 5 times
Notice the new()
. This is because we cannot (yet) instantiate through our “normal” way: tmp = foo()
. Basically, we call
the new() method, which instantiate it for us. This method is found in the base
class, a class that every object
extends from (actually, it will extends from base when no other extends is found). This base class has got all
functionality needed to deal with objects: the reference count, the name, the memory usage, functionality to make an
object read-only, functionality to clone, get parents, get interfaces, even get annotations (yes, we will implement
annotations in the core).
The road ahead
We currently have a few contributors who are really busy implementing all kind of cool stuff. But we can always use your help. We are focussing on getting modules running. Once we can “load” code from other files, we can setup modules (which are like bundles, or directories with classes grouped together). These modules are the main Saffire “currency”. You need a twitter-client? Install the (or a) twitter-module. Need a framework, install the framework module and you’re good to go. This system can be seen as ruby “gems”. Another nice thing, we try and implement a repository system for modules, and we try to keep things as safe as possible. Modules are by default signed by the author, and will be validated upon download/installing. It’s even possible to sign single Saffire bytecode files!
The module repository
The module repository will be very similar to repository systems like apt and yum. You can add your own repositories, which are nothing more than websites with a specific structure. You can search through all Saffire modules and their metadata, install them, update them to the latest version (or lock a specific version), upload new modules, etc etc etc.. It really deserves a special blogpost (and it will, as soon as we start with the system).