XTCLANG GUIDES
Introducing the Ecstasy language.
xtclang
syntax
structure
execution-model
Authored by: Abby Sassel, Cameron Purdy
Last edited: @January 11, 2024
About this guide
Learn about Ecstasy’s syntax, structure and execution model and discover the core principles that make Ecstasy an ideal language for the development of highly efficient and scalable cloud applications with a low carbon footprint.
Topics
- Introduction to Ecstasy's syntax.
- The design principles and building blocks of the Ecstasy language.
- A comparison of Ecstasy's language features with other programming languages in the C family.
Target Audience
If you would like to learn how to build highly efficient, scalable and secure cloud applications in Ecstasy, this introduction to Ecstasy guide is for you!
Prior experience developing with any of the C family of languages, such as Java, Kotlin, C# or C++ is helpful but not essential.
Ecstasy language and syntax
Ecstasy is a general-purpose programming language, designed for the development of highly efficient, scalable and secure cloud architectures.
Syntax Design
Ecstasy language is designed to be accessible for programmers who are comfortable with any of the C family of languages, such as Java, C# and C++. We wanted it to be a joy to learn and use as a new language, both in its familiarity as well as its thoughtful innovations.
Let's look at some illustrative examples:
Variable Declaration
Variable declaration should look familiar to folks coming from Java, C# and C++:
// general form:
// type variableName = value;
Boolean done = False;
Int count = 0;
String greeting = "hello";
Hello World
With a few exceptions, the Ecstasy "Hello World" example should feel familiar too:
module HelloWorld {
void run() {
@Inject Console console;
console.print("Hello World!");
}
}
Familiar, but different
Ecstasy’s syntax design is close to the C family of languages. However, it takes influence from many others including Kotlin, Ceylon, Scala, and Python.
This familiarity hides some fundamental differences in the design of the Ecstasy execution model. It is this model that we will describe here, before we proceed on to syntax and structure in other guides. The execution model is important to lay out up front because it motivates other aspects of Ecstasy's language design.
Execution Model
Before we dive into the details, here's a high-level overview of the execution model components:
- Containers
- Type System
- Ecstasy module
- Modules
- Classes
- Objects
- Services
- Fibers
Containers
A container is the highest-level abstraction in Ecstasy's execution model; it's where any and all code execution occurs.
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.
Secure by design
Security is the fundamental principle of the Ecstasy container model.
By default, containers have no access to their parent containers, runtime environment, network or other resources. More permissive access must be explicitly injected into a given 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 operating system (OS) capabilities, can only be represented within a container by injected interfaces.
Type System
A type system is a set of constraints, such as data types, operations and relationships, to prevent illegal program states.
Every Ecstasy container has a type system
All Ecstasy containers have a type system associated with them; all Ecstasy code running in a container is defined by and is part of that type system.
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.
Closed and immutable
Ecstasy 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.
A type can indicate explicitly immutability. An immutable object is always of an explicitly immutable type, so it is always easy to determine if an object is mutable or immutable.
- 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.
Module
A module is a unit of code organization describing classes, their relationships, methods and data.
A module is the unit of compilation, and the unit of versioning.
A type system in Ecstasy is composed from modules.
The Ecstasy language provides a core "ecstasy" module, which is automatically imported into every module and automatically included in every type system. This module contains the fundamental classes defined by the Ecstasy language: integers, booleans, strings, arrays, and so on.
Class
Ecstasy is class based; all objects are of a class, and all classes come from modules.
In Ecstasy, everything is an object and all objects have a type.
Service
A service in an object that represents the intersection of data ownership and code execution.
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.
A service represents a domain of mutable data. Mutable data can neither leave nor enter a service. All access to data and all mutation of data can only occur within the service that owns that data. Any attempt to access or modify data of a different service must occur within that different service, by proxy.
- Each service belongs to a container.
- Each container is a service.
- Each service is an object, and has a class.
Service boundary
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.
Each service executes asynchronously, concurrently, and when possible, in parallel.
Fiber
A fiber is the smallest unit of execution, which runs a given application task.
All execution of Ecstasy code occurs on 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. When a call is made to a service proxy, the calling service creates a future result, and the service that is being called creates a new fiber on which the incoming call will execute.
A call to a service proxy can be either synchronous or asynchronous. A synchronous call will block the calling fiber until a result is received from the called service.
Within any service, at most one fiber is permitted to be actively executing code at any one time; there is no parallel execution within a single service. Many fibers can exist concurrently within a service; when the currently executing fiber blocks or completes, another fiber within that service may begin executing.
When a fiber completes, its result (return values or exception) will complete the future that was created within the calling service. If the caller had made a blocking (i.e. synchronous) call to the service proxy, then the fiber that made the call will receive the result and be able to continue executing from that point.
A normal result from a blocking call to a service will transfer all returned value(s) to the calling fiber. An exceptional result from a blocking call to a service will raise an exception on the calling fiber.
That’s it! You now have an introduction to Ecstasy’s syntax, structure and execution model and the core principles that make Ecstasy an ideal language for the development of highly efficient and scalable cloud applications. The list of axioms above 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 Introduction to Ecstasy guide from time to time, as you work through any of our subsequent guides.
EXPLORE & LEARN
Ready to learn more?
Check out our latest guides, blogs and tutorials!