2010-05-18
ATS - Applied Type System Programming Language
The release of Version 0.2.0 of ATS was recently announced on the ATS mailing list. From the ATS website:
ATS is a programming language with a highly expressive type system rooted in the framework Applied Type System. In particular, both dependent types and linear types are available in ATS. The current implementation of ATS (ATS/Anairiats) is written in ATS itself.
The Computer Language Benchmarks Game show's ATS as being similar to C/C++ in terms of performance.
Compilation from source follows the standard 'configure' and 'make'. Once compiled you need to set an ATSHOME environment variable along with adding the bin directory to the path. Instructions on what these should be set to are displayed after compilation is finished.
$ ./configure
...
$ make
$ ...
ATS/Anairiats has been built up successfully!
The value of ATSHOME for this build is "/home/foo/ats".
$ export ATSHOME=/home/foo/ats
$ export PATH=$PATH:$ATSHOME/bin
'atscc' is used to compile an ATS program to C and then compile the C code to an executable. A simple 'Hello World' ATS program is:
implement main() = print("Hello World\n");
Place that code in a 'hello.dats' file and compile:
$ atscc -o hello hello.dats
atsopt --output hello_dats.c --dynamic hello.dats
gcc ... -o hello hello_dats.c -lats
$ ./hello
Hello World
When running 'atscc' you can see the commands it spawns to do the compilation. It runs 'atsopt' to generate the C code and 'gcc' to compile the C code. The resulting executable on my Ubuntu Linux system is about 13Kb when stripped. The commands and options are explained in the ATS manual.
ATS feels like a hybrid of C and ML. Code is written in an ML style but you can embed C directly and call ATS functions from C or C functions from ATS. You can control memory at a low level, optionally include garbage collection, and use the type system to ensure that memory is safely accessed and released.
A quick example of calling C from ATS is below:
%{^
#include <ogg/ogg.h>
%}
abst@ype ogg_sync_state = $extype "ogg_sync_state"
extern fun ogg_sync_init (oy: &ogg_sync_state?): int = "#ogg_sync_init"
extern fun ogg_sync_clear(oy: &ogg_sync_state?): int = "#ogg_sync_clear"
implement main() = let
var state: ogg_sync_state?;
val r = ogg_sync_init(state);
val () = printf ("ogg_sync_init: %d\n", @(r));
val r = ogg_sync_clear(state);
val () = printf("ogg_sync_clear: %d\n", @(r));
in
()
end
This can be compiled and run (assuming libogg is installed and the above is in ogg.dats) with:
$ atscc -o ogg ogg.dats -logg
...
$ ./ogg
ogg_sync_init: 0
ogg_sync_clear: 0
C code is directly included using '%{ ... %}'. A variant of this is '%{^ .... %}' which places the C statements at the top of the compiled ATS code. This is what I use for including the libogg header above. libogg has a C struct type called 'ogg_sync_state'. This is exposed to ATS using the '$extype "ogg_sync_state" definition. The C functions are defined with an ATS function definition matching the C definition and the '= "#ogg_sync_init"' at the end states that it is implemented in an external C library under the given name.
The argument passed to the C function is given as 'oy: &ogg_sync_state?'. The means the argument name is 'oy' and it is an ogg_sync_state object passed by pointer (The '&' part). The '?' at the end means it can be unintialized. The code that calls these routines looks very C like:
var state: ogg_sync_state?;
val r = ogg_sync_init(state);
The C code generated by this is actually:
ATSlocal (ogg_sync_state, tmp1) ;
ATSlocal (ats_int_type, tmp2) ;
tmp2 = ogg_sync_init ((&tmp1)) ;
This exactly equivalment to hand coded C. Creating the structure on the stack and calling the libogg function passing it a pointer to it.
The above is only one way of calling C routines. There is much more flexibility and you can use the type system to express an impressive amount of compile type safety checking. See the 'fgets' example at the end of this ATS for ML programmers page. Another good example is this Cairo tutorial which demonstrates using linear types to keep track of Cairo objects. It becomes a compile time error not to call the appropriate Cairo functions to release resources.
Some other interesting reads to learn about ATS: