More turtles

The Ecstasy type system is called a Turtles Type System, because "it's turtles, the whole way down". This is, in many ways, a revolutionary approach to type systems. Object type systems have traditionally had primitive types (like a "periodic table of elements" for the language) from which all other types are built, but in Ecstasy things are a bit different. For example, an Ecstasy integer is composed of an array of bits, each of which is composed of an integer literal (0 or 1), which is in turn composed of a string, which is composed of an array of characters, each of which is composed of an integer. So we're right back where we started, with an integer -- and you can just recurse infinitely, because the types are all turtles.

Making a type system like this actually work is a challenge, so it didn't appear all at once. Recently, support for recursive type definitions was added, in order to support the JSON parsing project. Consider the following Ecstasy code:

 * JSON primitive types are all JSON values except for arrays and objects.
typedef (Nullable | Boolean | IntLiteral | FPLiteral | String) Primitive;

 * JSON types include primitive types, array types, and map types.
typedef (Primitive | Map<String, Doc> | Array<Doc>) Doc;

Here, in two lines of code (which could even be simplified to a single line, if we didn't want to split out primitive JSON values), we see a complete Ecstasy mapping of the JSON specification. That second typedef, though, is a doozy, because it refers to itself. If you stop and read it carefully it makes a lot of sense: A JSON document is either a primitive value, a map of string keys to JSON values (each of which could be an entire recursive document structure), or an array of JSON values (each of which could be an entire recursive document structure).

To keep it simple, consider the following example:
typedef (Int | List<Manifold>) Manifold;

Manifold m1 = 9;
Manifold m2 = [m1];
Manifold m3 = [m2];

When executed, this code will print:
But the amazing thing isn't that it works at all, but rather that it works with full type safety.


Hello World!

In retrospect, the most obvious missing feature of Ecstasy is the prototypical "Hello World!" example.

The earliest adopters / experimenters / hackers who have been playing with Ecstasy for some time now were somehow able to divine the magic incantations necessary to get get code compiling and running (sometimes with help from our team), but it's time to make this process much easier.

This won't be a single update; rather, it is a process -- of moving the project from a small team that knows all of the undocumented nooks and crannies, out into the public sphere. The initial experience with Ecstasy should not be as soul-sucking and psychologically scarring as a Google job interview. For a new user, it should be straight-forward to get started, and not some experience like an "obstacle course" or "running the gauntlet".

To that end, we introduce step one, the Hello World:
module HelloWorld
    void run()
        @Inject Console console;
        console.println("Hello World!");
Here's a short explanation of the code, which is found in ./xsrc/examples/HelloWorld.x:
  • A module is the unit of compilation, loading, linking, and execution, so we need to write one of those. Don't worry -- as you can see, it's easy.
  • The TestConnector (which we'll cover below) looks for a method on the module called "run" that takes no parameters. (The module is a class, so "void run()" on the module is just a normal method.)
  • Ecstasy code is purposefully incapable of doing any I/O; for security reasons, there is nothing in the language (or in the compiled form of the language) that has any access to any hardware or OS resource. As a result, the code must depend on its container to provide something that implements the Console interface; this is called injection. The behavior of the console that is injected by the TestConnector is to print to stdout.
  • The declaration "@Inject Console console;" declares a read-only variable called console, and when it is de-referenced. it will always have a value that is a Console. (It is a contract; if the container could not -- or chose not to -- provide a Console, then the creation of the container itself would have failed.)
  • Hopefully, the line that prints out "Hello World!" is self-explanatory.
Here are the steps to get started:
  1. Download and install a recent JDK, if you don't already have one. For example, we are currently using JDK 11 from the Amazon Corretto project.
  2. Download IntelliJ IDEA, if you don't already use it. (Or update it to the latest version, if you already use it.) Since Ecstasy is an open source project on GitHub, you can use the "Community" edition of IDEA -- but we do think that it is an IDE worth paying for, so don't be afraid to splurge on the "Ultimate" edition!
  3. Install IDEA and start it up. It should give you a dialog that looks like this, on which you choose the "Check out from Version Control" option:
  4. For the URL, type https://github.com/xtclang/xvm.git, and for the directory, place it in your own development area:
  5. Press Clone to proceed, and after the clone completes, IDEA should ask if you want to open the project; select Yes.
  6. You may have to register the JDK with IDEA. To do this, open the IDEA "Project Structure" dialog, and under "Platform Settings" / "SDKs", press the "+" button, specify the location of the JDK, and then name it "Java 11".
  7. JUnit is already part of IDEA, but you may have to register it as a named library so that this project can find it. To do this, open the IDEA "Project Structure" dialog, and under "Platform Settings" / "Global Libraries", press the "+" button, specify the location of the library, and press OK. (On the Mac, the location will be something like /Applications/IntelliJ IDEA CE.app/Contents/lib/junit.jar and junit-4.12.jar.)

    ... and ...
  8. Under the IDEA "Build" menu, choose "Rebuild Project". This should complete with no errors (but a few warnings).
  9. Under the IDEA "Run" menu, choose "Edit Configurations", press the "+" button, select the "Application" option, and set Name to "Hello World!", Main class to "org.xvm.runtime.TestConnector", VM options to "-Xms256m -Xmx1024m -ea", Program arguments to "HelloWorld ./examples/HelloWorld.x", working directory to "/Users/elonmusk/Development/xvm/xsrc" (or whatever the path is on your own machine), and press OK.
  10. In the menu bar area, choose Hello World! and press the green arrow to run it!

    ... and the output should look like this: