Skip to content
Cameron Purdy edited this page Jan 19, 2023 · 14 revisions

Foreword

When is the last time that you learned a new language? I mean, legitimately and truly learned a new language, in detail, and in depth?

It's not an easy undertaking to learn a new language. Many of the words used to describe the new language will look and sound like words that you already know, but now each word seems to have a slightly different meaning, and some words will contain surprising twists that aren't entirely obvious at first. It may seem like there's an entirely different set of assumptions about what words mean, how things work, what styles should be embraced, and what programming approaches should be avoided.

It's this enormous chasm -- or maybe just this minor crack in the sidewalk -- that this guide will help you safely cross. We will work to make the unfamiliar seem simple and natural, and the new and different seem simultaneously obvious and necessary. That's a tall order, and if you think of anything along the way that can make the process simpler and clearer, please let us know on our discussion forum. The same goes for questions that you might have, or edits that we should incorporate.

And now, without further ado ...

Introduction to the Ecstasy Language

Ecstasy is a programming language that will seem very familiar in many ways to any programmer who knows Java, C#, or C++. Its syntax design is intentionally similar to these languages, with bits and pieces influenced by other languages in the same general family, including Kotlin, Ceylon, Scala, and even Python. We wanted the syntax to feel familiar, like a favorite well-worn glove. And we wanted it to be a joy to learn and use as a new language, both in its familiarity, and also in its thoughtful innovations.

To illustrate this sense of familiarity, we're pretty sure that you won't need a detailed explanation to grok the basics of this Ecstasy code:

Boolean done     = False;
Int     count    = 0;
String  greeting = "hello";

And while there may be a few details that raise questions, there is probably nothing baffling about the Ecstasy "Hello World" example, either:

module HelloWorld
    {
    @Inject Console console;
    void run()
        {
        console.print("Hello World!");
        }
    }

Yet this simple familiarity also hides some fundamental differences in the design of the Ecstasy execution model. It is this model that we will briefly describe here, before we proceed on to the easy aspects of the language like syntax and structure. This fundamental model is important to lay out up front, because understanding it will make almost everything else seem obvious.

We're going to fly through these topics, laying out statements of fact without many supporting details. We promise that each of these topics will be examined in depth later in this language guide, but for now, try to accept these statements as axioms of the language -- even if these points temporarily raise more questions than they answer.

Containers

All execution of Ecstasy code occurs within an Ecstasy container; if Ecstasy code is running, it is running inside of an Ecstasy container.

An Ecstasy container has a type system; all Ecstasy code running in a container is defined by and is part of that type system.

Ecstasy containers are arranged hierarchically, like directories in a file system. But unlike a file system, it is not possible to navigate from a nested container up to its parent container; a parent container is invisible and inaccessible to any of the containers nested within it. Like directories, nesting is recursive, and can be arbitrarily deep.

Type systems are both closed and immutable. Closed means that there are no dangling pointers; it is illegal for a type system to not be fully consistent with itself, and the type compositions in the type system are fully structurally verifiable by the rules of the XVM. Immutable means that new code cannot be introduced within a type system on the fly; once a container is created, its type system is guaranteed to be immutable.

New type systems can be created on the fly, and new nested containers can be created on the fly using those new type systems. As a result, it is possible to safely introduce new code, on the fly, into a running system -- but only in the form of a new container.

The deliberate safety of the container model is the result of the new container having no access to its parent container, or to its runtime environment, including the machine, the OS, the network, the local storage, and so on, unless that access is explicitly injected into the new container by its parent container. Furthermore, all access injected into a container is injected by interface, such that no other reflective details exist -- even using reflection, only the members of the interface exist on the injected object.

Ecstasy does not have a Foreign Function Interface (FFI); this was a careful and purposeful decision. No native code can exist inside of an Ecstasy container. All potentially-native operations, including all OS capabilities, can only be represented within a container by injected interfaces.

Security is the fundamental principle of the Ecstasy container model.

Type System

A type system is composed from modules.

Ecstasy is class based; all objects are of a class, and all classes come from modules.

In Ecstasy, everything is an object, and everything has a type.

The Ecstasy language provides a core "ecstasy" module, which is automatically present in every type system. This module contains all of the fundamental classes defined by the Ecstasy language, including integers, booleans, strings, arrays, and so on. Even the most basic types in Ecstasy are classes, and even the most basic values are objects.

Immutability

Objects can be immutable. Immutable state cannot be modified.

An object can be instantiated immutable, or an object can be made immutable. Once an object is immutable, it cannot be made mutable again.

Immutability is an explicit part of the type system. A type knows if it is explicitly immutable. An immutable object is always of an explicitly immutable type, so it is always easy to determine if an object is mutable or immutable.

Services

Each service belongs to a container.

All execution of Ecstasy code occurs within an Ecstasy service; if Ecstasy code is running, it is running as part of an Ecstasy service inside of an Ecstasy container.

Each container is a service.

Each service is an object, and has a class.

Any object passed into a service from another service goes through a service boundary. The only objects that can go through a service boundary are either (i) other services, or (ii) immutable objects.

When a reference to a service object is passed through a service boundary, the object that appears inside the target service boundary is a service proxy. Any call made to a service proxy will go back out through the service boundary to the other service represented by the proxy.

With respect to all other services, each service executes asynchronously, concurrently, and when possible, in parallel.

When a call is made to a service proxy, the service represented by the proxy creates a new fiber to execute the incoming call.

All execution of Ecstasy code occurs within a fiber within an Ecstasy service; if Ecstasy code is running, it is running on a fiber as part of an Ecstasy service inside of an Ecstasy container.

Within any service, at most one fiber is permitted to be executing at a time. Many fibers can exist concurrently within a service; when one fiber stops executing (or is waiting for a different service to respond), another fiber within that service may begin executing.

A service represents a mutable domain of state. Mutable information can neither leave nor enter a service. All access to state and all mutation of state can only occur within the service that owns that state. Any attempt to access or modify state of a different service must occur by proxy.

Moving on ...

That list of axioms may seem overwhelming at first, but the design will become increasingly obvious as each new concept is explained. Don't be afraid to come back and re-read this section from time to time as you work through the subsequent chapters.

Next: Creating your first module