Recent from talks
Nothing was collected or created yet.
E (programming language)
View on Wikipedia
| E | |
|---|---|
| Paradigm | Multi-paradigm: object-oriented, message passing |
| Designed by | Mark S. Miller |
| First appeared | 1997 |
| Typing discipline | Strong, dynamic |
| OS | Cross-platform |
| License | Portions in different free licenses |
| Website | erights |
| Major implementations | |
| E-on-Java, E-on-CL | |
| Influenced by | |
| Joule, Original-E, Java | |
| Influenced | |
| Pony | |
E is an object-oriented programming language for secure distributed computing, created by Mark S. Miller,[1] Dan Bornstein, Douglas Crockford,[2] Chip Morningstar[3] and others at Electric Communities in 1997. E is mainly descended from the concurrent language Joule and from Original-E, a set of extensions to Java for secure distributed programming. E combines message-based computation with Java-like syntax. A concurrency model based on event loops and promises ensures that deadlock can never occur.[4]
Philosophy
[edit]The E language is designed for computer security and secure computing. This is performed mainly by strict adherence to the object-oriented computing model, which in its pure form, has properties that support secure computing. The E language and its standard library employ a capability-based design philosophy throughout in order to help programmers build secure software and to enable software components to co-operate even if they don't fully trust each other. In E, object references serve as capabilities, hence capabilities add no computational or conceptual overhead costs. The language syntax is designed to be easy for people to audit for security flaws. For example, lexical scoping limits the amount of code that must be examined for its effects on a given variable. As another example, the language uses the == operator for comparison and the := operator for assignment; to avoid the possibility of confusion, there is no = operator.
Computational model
[edit]In E, all values are objects and computation is performed by sending messages to objects. Each object belongs to a vat (analogous to a process). Each vat has a single thread of execution, a stack frame, and an event queue. Distributed programming is just a matter of sending messages to remote objects (objects in other vats). All communication with remote parties is encrypted by the E runtime. Arriving messages are placed into the vat's event queue; the vat's event loop processes the incoming messages one by one in order of arrival.
E has two ways to send messages: an immediate call and an eventual send. An immediate call is just like a typical function or method call in a non-concurrent language: a sender waits until a receiver finishes and returns a value. An eventual send sends a message while producing a placeholder for a result called a promise. A sender proceeds immediately with the promise. Later, when a receiver finishes and yields a result, the promise resolves to a result. Since only eventual sends are allowed when communicating with remote objects, deadlocks cannot happen. In distributed systems, the promise mechanism also minimizes delays caused by network latency.
Syntax and examples
[edit]E's syntax is most similar to Java, though it also bears some resemblance to Python and Pascal. Variables are dynamically typed and lexically scoped. Unlike Java or Python, however, E is composed entirely of expressions. Here is an extremely simple E program:
println("Hello, world!")
Here is a recursive function for computing the factorial of a number, written in E. Functions are defined using the def keyword.
def factorial(n :int) :int {
if (n == 1) {
return 1
} else if (n > 0) {
return n * factorial(n-1)
} else {
throw("invalid argument to factorial: "+n)
}
}
In the first line, :int is a guard that constrains the argument and result of the function. A guard is not quite the same thing as a type declaration; guards are optional and can specify constraints. The first :int ensures that the body of the function will only have to handle an integer argument. Without the second :int above, the function would not be able to return a value. Being able to see up front that information escapes out of the function is helpful for security auditing.
Since E is intended to support secure co-operation, the canonical example for E programs is the mint, a simple electronic money system in just a few lines of E. The following code defines a function that makes mints, where each mint has its own currency. Each mint can make purses that hold its currency, and any holder of two purses of the same currency can securely transfer money between the purses. By quick examination of the source code, an E programmer can easily verify that only mints may change the amount of money in circulation, that money can only be created and not destroyed, that mints can only create money of their own currency, and that only the holder of a purse can change its balance.
def makeMint(name) :any {
def [sealer, unsealer] := makeBrandPair(name)
def mint {
to makePurse(var balance :(int >= 0)) :any {
def decr(amount :(0..balance)) :void {
balance -= amount
}
def purse {
to getBalance() :int { return balance }
to sprout() :any { return mint.makePurse(0) }
to getDecr() :any { return sealer.seal(decr) }
to deposit(amount :int, src) :void {
unsealer.unseal(src.getDecr())(amount)
balance += amount
}
}
return purse
}
}
return mint
}
Objects in E are defined with the def keyword, and within the object definition, the to keyword begins each method. The guard expressions in this example illustrate how to specify a value constraint (as in :(int >= 0) or :(0..balance)).
The mint example makes use of a built-in mechanism called a sealer. The function makeBrandPair creates two associated objects, a sealer and an unsealer, such that the sealer can seal an object in a box and the unsealer is the only object that can retrieve the contents of the box. See the E website for a more detailed explanation of this money example.[5]
See also
[edit]References
[edit]- ^ Handy, Alex (14 November 2016). "The future of software security". SD Times.
- ^ Seibel, Peter (21 December 2009). Coders at Work: Reflections on the Craft of Programming. Apress. pp. 95–96. ISBN 9781430219491.
- ^ "E's History". www.erights.org.
- ^ Miller, Mark S.; Tribble, E. Dean; Shapiro, Jonathan (2005). "Concurrency Among Strangers" (PDF). Trustworthy Global Computing. Lecture Notes in Computer Science. 3705: 195–229. Bibcode:2005LNCS.3705..195M. doi:10.1007/11580850_12. ISBN 978-3-540-30007-6. Archived from the original (PDF) on 2022-03-31. Retrieved 2021-03-05.
- ^ Rees, Jonathan; Miller, Mark (2001). "From Objects To Capabilities - Simple Money". erights.org. ERights. Retrieved 8 July 2014.
Before presenting the following simple example of capability-based money, we must attempt to head off a confusion this example repeatedly causes. We are not proposing to actually do money this way! A desirable money system must also provide for...
External links
[edit]E (programming language)
View on GrokipediaHistory and Development
Origins and Influences
The E programming language was created in 1997 by Mark S. Miller and a team including Dan Bornstein, Douglas Crockford, and Chip Morningstar at Electric Communities, a company focused on developing secure software for online interactions.[6][7] This effort built on earlier work at the company, aiming to provide a robust foundation for distributed computing in an era of emerging internet-based applications. E drew significant influences from several prior systems to achieve its goals of secure concurrency and distribution. It descended from Joule, a concurrent dataflow language developed in 1994 at Agorics by Miller, Dean Tribble, and Norm Hardy, which introduced concepts like channels and promise pipelining for distributed event handling.[8] Additionally, E evolved from Original-E, an early prototype that extended a capability-secure subset of Java with Joule's concurrency features to enable secure distributed programming.[7] Java itself influenced E's syntax and object model, providing a familiar structure while enhancing it for security.[9] The initial development of E was driven by the need to address security vulnerabilities in distributed applets and electronic commerce systems, where untrusted code could compromise remote interactions.[9] Electric Communities used Original-E to prototype Habitats, a secure, decentralized social virtual reality system, demonstrating E's potential for persistent, distributed environments.[7] E made its first public appearance through these prototypes, with the full language open-sourced by Electric Communities in 1998, fostering further community-driven evolution.[7]Key Contributors and Evolution
The E programming language was led in its development by Mark S. Miller, with significant contributions from Dan Bornstein, Douglas Crockford, and Chip Morningstar, primarily during their time at Electric Communities in the mid-1990s.[3][10] Additional early collaborators on prototypes included Doug Barnes, Gordie Freedman, and Eric Messick at Communities.com.[3] Development began in 1997 with prototypes of Original-E at Communities.com, evolving from the Joule language to address secure distributed object systems, informed by experiences with the EC-Habitats beta, a platform for secure virtual realities.[3] Post-1997, the language was refined into E proper, emphasizing robust security and distributed persistence, with ongoing input from contributors like Bill Frantz, Jamie Fenton, and Bob Schumaker.[3] The project spun out as the Open E Project, transitioning to open-source distribution, with core implementations placed in the public domain to encourage community involvement.[3][11] Stable releases emerged in the late 1990s and 2000s, such as E 0.8.12 (circa 2000), which underwent security review by experts David Wagner and Dean Tribble, and later versions like 0.8.24 (circa 2002), which approximately doubled performance over earlier builds, and 0.9.3 (circa 2006), which fixed bugs and improved compatibility.[12][11] Subsequent iterations addressed bugs and compatibility issues, such as serialization changes in CapTP for distributed communication.[11] Minor updates continued through the 2000s by figures like Marc Stiegler and Tyler Close, focusing on refinements to event loops and persistence support.[3] No major developments or releases have occurred since the early 2010s, with the language entering a phase of maintenance rather than active evolution, as evidenced by the stasis in official repositories and documentation as of 2025.[11] E's capability-based security and actor-inspired model have nonetheless influenced subsequent projects, including the Pony language from 2015 onward, which adopts similar principles for safe, high-performance concurrency in actor-model systems.Design Philosophy
Security and Capability Principles
E employs a capability-based security model where object references serve as unforgeable capabilities, enabling access control solely through possession of these references. In this system, an object can only interact with another if it holds a valid reference to it, which is obtained explicitly from the object's creator or through authorized delegation; references cannot be forged, guessed, or manufactured due to the absence of pointer arithmetic, mutable statics, and global naming authorities. This design ensures that unauthorized access is fundamentally impossible, as third parties lack the means to obtain or impersonate references, even in distributed environments where communication is encrypted.[13][9] Central to E's security is the principle of least authority (POLA), which mandates that each entity—whether a program, module, or object—receives only the minimal set of authorities necessary to fulfill its designated role, enforced dynamically at runtime. For instance, a word processor object might be granted read/write access to a single user file and read-only access to font resources, but no broader filesystem privileges, thereby confining potential damage if the code is compromised or behaves maliciously. This granular approach reduces the attack surface multiplicatively across scales, from human users to individual objects, by aligning authority precisely with duties and preventing over-authorization.[9][14] Unlike traditional access control lists (ACLs), which rely on name-centric, static permissions tied to identities and checked against a central or distributed ledger, E's capabilities provide superior security in distributed settings by treating references as self-contained, opaque tokens of authority that can be safely passed without revealing underlying identities or requiring trusted intermediaries. ACLs suffer from issues like the confused deputy problem—where a principal is tricked into misusing its ambient authority—and revocation challenges in dynamic networks, whereas capabilities inherently bundle designation with attenuated authority, enabling compositional revocation through patterns like forwarders or membranes without global coordination. This key-centric model supports robust, decentralized cooperation among untrusted components, avoiding the topology-based vulnerabilities of ACLs, such as namespace ambiguities and single points of failure.[14][9] E's security principles originated from efforts at Agorics Inc. in the early 1990s, where researchers including Mark S. Miller and Dean Tribble developed the Joule language to support secure, market-based distributed computing for electronic commerce and digital money systems. Motivated by the need to prevent fraud and ensure tamper-proof transactions in open networks—drawing lessons from vulnerabilities in early electronic cash prototypes—Joule introduced secure channels combining the actor model with logic variables, influencing E's evolution toward capability-secure smart contracting. This foundation addressed the dual challenges of concurrency and access control in persistent, distributed applications, extending pure-capability architectures like KeyKOS to enable verifiable economic interactions without centralized trust.[15][16]Auditability and Object Cooperation
E's design emphasizes auditability through its adherence to strict lexical scoping rules, which enable static verification of how authority is used and propagated within code. By evaluating names in the caller's namespace and binding variables at the point of nested function or object creation, E limits the scope of potential authority leaks to well-defined lexical contours, facilitating comprehensive code reviews without global state interference. This approach enforces object-capability discipline, where references to powerful objects must be explicitly passed, making unintended access patterns immediately visible during static analysis.[17][9] To further enhance auditability and prevent confusion in aliasing or identity-related vulnerabilities, E employs distinct operators for common operations. The== operator performs identity (sameness) comparison on references, generalizing reference equality from languages like Java, while structural equality is handled through mechanisms such as pattern matching or object methods. Similarly, := is used exclusively for variable assignment and definition, rendering the single = invalid to eliminate accidental mutations during equality testing. These syntactic choices, combined with the avoidance of shared mutable state, ensure that code intent is unambiguous and reduce the cognitive load for auditors examining authority flows.[18][19]
Object cooperation in E is achieved securely through asynchronous message passing, where objects interact solely via explicit references without direct access to shared mutable state, thereby eliminating hidden side effects and race conditions. Messages are sent using the eventual-send operator (<-), which enqueues deliveries in a fail-stop FIFO manner across distributed vats, preserving causality and enabling verifiable temporal isolation between sender and receiver plans. This model supports dynamic composition of objects into composites, where facets expose only necessary interfaces, ensuring that cooperation remains confined and auditable without implicit dependencies.[9]
At its core, E embodies a "secure by construction" philosophy for distributed software, where the object-capability model—briefly referencing capabilities as unforgeable references—integrates with message passing to enforce the Principle of Least Authority (POLA) dynamically. By reifying authority distinctions in the reference graph and restricting interactions to overt channels, E minimizes vulnerability multiplication, allowing robust cooperation even among mutually suspicious principals while maintaining encapsulation and fault isolation. This design prioritizes verifiable safety over flexibility, making distributed systems resilient to both accidental and malicious interference.[9]
Computational Model
Vats and Event Queues
In the E programming language, a vat serves as the fundamental unit of computation, analogous to a process but designed as an isolated, single-threaded execution environment containing a heap of objects, a stack for immediate calls, and an event queue for pending message deliveries.[20] This structure turns the traditional programming model inside-out by making all external interactions message-driven rather than direct procedure calls, ensuring that each vat operates independently on its host machine without shared mutable state across boundaries.[21] Vats provide the minimal unit for persistence, resource control, and protection against denial-of-service attacks, with each object residing in exactly one vat.[20] The event queue within a vat holds pending deliveries, which are pairs consisting of a message and its intended recipient object, enqueued via asynchronous eventual sends from other objects, potentially in remote vats.[21] The vat's event loop operates as a non-blocking, turn-based mechanism: in each turn, the single thread dequeues one delivery, executes it synchronously to completion—processing any nested immediate calls on the stack—and then advances to the next, guaranteeing temporal isolation and preventing intra-vat concurrency.[20] Immediate calls, which occur synchronously within the same vat using near references, allow for efficient local computation without queueing, while all cross-vat interactions remain deferred and message-driven to maintain this single-threaded discipline.[21] By enforcing no shared mutable state between vats—where only eventual references carrying asynchronous messages can cross boundaries—E's vat model eliminates race conditions and deadlocks that plague traditional multithreaded systems, as vats communicate solely through eventual message passing.[20] This design draws from the actor model, where vats function as isolated actors processing messages sequentially, but extends it with capability-based security to enforce object access control and prevent unauthorized interactions.[20]Promises and Message Passing
In the E programming language, communication between objects occurs through message passing, distinguishing between synchronous immediate calls and asynchronous eventual sends to support distributed and concurrent execution. An immediate call, using the dot operator (.), is employed for local interactions within the same vat—E's unit of concurrency—and blocks the sender until the receiver completes the operation, ensuring a direct outcome.[22] In contrast, an eventual send, denoted by the arrow operator (<-), facilitates asynchronous messaging, particularly across vats or in distributed settings, where the sender immediately receives a promise representing the future result without blocking.[7] This design separates the act of sending from awaiting resolution, promoting non-blocking progress in potentially remote interactions.[22] Promises in E serve as placeholders for eventual outcomes, enabling composable asynchronous operations by allowing senders to continue execution while deferring result handling. Upon completion, a promise is resolved either by fulfillment with a value—via a resolver's resolve method—or by breaking with an exception through the smash method, propagating the issue without crashing the program.[7] This resolution mechanism supports failure containment, as broken promises can be caught and managed explicitly, fostering robust distributed systems where operations chain without synchronous dependencies.[22] Promises are first-class entities, treatable as ordinary references for passing in further messages, which underpins their role in building layered, asynchronous workflows.[23] The eventual semantics of message passing inherently prevent deadlocks by eliminating blocking cycles in distributed calls, as no sender waits for a response before proceeding. Unlike traditional RPC models that risk circular dependencies across processes, E's asynchronous sends ensure that messages queue in event loops without requiring mutual suspension, guaranteeing progress even in multi-vat scenarios.[7] This deadlock freedom arises from the language's commitment to temporal decoupling, where promises defer synchronization until explicitly requested via constructs like when clauses, avoiding inadvertent stalls.[22] For multi-step distributed transactions, promises enable chaining, where the outcome of one eventual send becomes the input for the next, optimizing communication through pipelining. In a sequence such as initiating a remote computation followed by processing its result on another object, unresolved promises are forwarded as arguments or targets, allowing all messages to stream in a single network packet rather than requiring sequential round trips.[23] This reduces latency significantly—for instance, collapsing three conventional exchanges into one—while maintaining eventual consistency, as resolutions propagate forward once available, supporting efficient client-server patterns without upfront resolution.[7]Syntax and Semantics
Core Syntax Elements
E's syntax draws heavily from Java, employing curly braces to delimit blocks, familiar operators, and a structure that supports object-oriented programming, while incorporating dynamic typing and elements tailored to its capability-based security model. Statements are semicolon-optional, allowing separation by newlines for readability, much like Python, but the overall feel remains close to Java's imperative style. This design facilitates readability for developers familiar with mainstream languages, yet introduces constructs that enforce secure object interactions without traditional class hierarchies.[24][25] Central to E's syntax is thedef keyword, used for defining immutable variables, functions, and objects. For instance, def x := 42 declares a constant, while def add(a, b) { return a + b } defines a function; more complexly, def counter { var count := 0; to increment() { count += 1; return count } } creates an object with state and methods. Unlike class-based languages, E eschews classes entirely—everything is an object instantiated via such definitions, with methods prefixed by the to keyword to denote callable behaviors. This object-centric approach ensures that all code operates within secure, capability-mediated boundaries, promoting encapsulation without inheritance.[26][27][25]
Guards enhance definitions by adding constraints, often for type checking or authority verification, integrated directly into parameter lists or bindings. Syntax like def safeDivide(x :(float64 > 0), y :float64) :float64 { return x / y } specifies that inputs must match the float64 guard and, for x, exceed zero, with mismatches triggering exceptions at runtime. These guards are not static types but dynamic assertions, aligning with E's emphasis on verifiable security. Pattern matching via match further refines control flow, as in match expr { pattern1 => result1; pattern2 ? guard => result2; matcher _ { fallback } }, allowing destructuring and conditional dispatching in a concise, functional manner.[26][25]
Control structures such as if, while, and for mirror Java's, but integrate seamlessly with E's dynamic and secure primitives, as detailed in subsequent sections on typing.[27]
Typing and Control Structures
E features a strong, dynamic typing system in which type checking occurs at runtime, allowing variables to hold values of any type without prior declaration, similar to languages like Smalltalk or Python.[28] This approach enables flexible code that adapts to runtime conditions, with type errors raising exceptions only when mismatched operations are attempted.[27] Unlike statically typed languages, E does not enforce type constraints during compilation, promoting rapid development while relying on runtime verification for safety.[28] To provide optional type hints and enforce contracts without static overhead, E uses guards, which are runtime assertions applied to variables, parameters, or return values. For example, a guard like:int coerces a value to an integer if possible or throws an exception otherwise, as in def x :int := "42".[27] Guards such as :near (for local objects), :rcvr (for remote references), or custom ones like notNull (to reject null values) ensure semantic contracts, including authority and locality, without halting the entire program; failures typically result in broken references or localized exceptions.[28] These optional annotations, denoted by a colon (e.g., :type), act as dynamic hints rather than strict static types, balancing expressiveness with security in distributed contexts.[27]
E's control structures emphasize simplicity and safety, drawing from familiar imperative paradigms while integrating runtime resolution for asynchronous elements. The if statement evaluates conditions immediately and requires braces for blocks, returning the value of the executed clause:
if (a > b) {
a
} else {
b
}
if (a > b) {
a
} else {
b
}
else and chained else if forms.[27] For multi-way branching, E provides match as a pattern-matching construct akin to a switch, allowing guards on patterns for type-safe dispatching:
match expr {
p1 => body1
p2 ? guard => body2
_ => default
}
match expr {
p1 => body1
p2 ? guard => body2
_ => default
}
for loops over iterables like ranges, lists, or maps, with syntax that avoids mutable indices for safety:
for i in 1..10 {
println(i)
}
for key => value in myMap {
process(key, value)
}
for i in 1..10 {
println(i)
}
for key => value in myMap {
process(key, value)
}
escape expression for non-local control flow, enabling structured exits similar to labeled breaks or lightweight exceptions. An escape block defines an ejector that can be invoked to exit early, catching the result in a downstream clause:
def result := escape ej {
while (true) {
if (found) {
ej(value) // Exit with value
}
}
} catch ej value {
value // Handle exited value
}
def result := escape ej {
while (true) {
if (found) {
ej(value) // Exit with value
}
}
} catch ej value {
value // Handle exited value
}
try/catch/finally handles standard exceptions from operations like division by zero.[27]
E avoids pervasive null references by design, initializing unassigned object variables to safe defaults and using guards like notNull to prevent null propagation in contracts. Safe null checks employ equality comparisons, such as if (obj == null) { ... }, or pattern guards in matches to verify non-nullness without unsafe dereferences.[28] This approach minimizes null-related errors, aligning with E's capability-based security model where absent references are explicitly managed rather than implicitly null.[27]
Language Features
Concurrency and Distribution
E's concurrency model is built around event loops, with one loop per vat, enabling parallelism without the use of traditional threads. This approach allows multiple vats to execute concurrently across a single machine or distributed systems, where each vat processes its events sequentially in a non-preemptive manner. By design, E avoids shared mutable state between vats, eliminating the need for locks and reducing the risk of race conditions or deadlocks inherent in multi-threaded programming.[29][21] Distribution in E is achieved through semi-transparent networking, where the same syntactic constructs apply to both local and remote object interactions. Local calls use near references for synchronous communication within a vat, while remote calls employ eventual references for asynchronous message passing over networks, accommodating latency and potential failures. Eventual sends, denoted by the<- operator, queue messages for delivery without blocking the sender, ensuring that distributed programs maintain correctness even when objects are relocated to the same vat. Secure remote references are facilitated by capability-based access control, allowing cross-platform distribution while preserving security boundaries between address spaces.[30][31]
This model offers significant advantages over conventional threading paradigms, as E's event-driven concurrency promotes reliability in distributed environments by treating all interactions as messages rather than direct state modifications. For instance, a simple distributed call might appear as bob <- greet(carol), which works identically whether bob and carol are local or remote, with the system handling serialization and queuing transparently. Promises, used to resolve eventual sends, further support composable asynchronous operations without introducing complexity into the core concurrency primitives. Overall, E's design facilitates scalable, secure distributed applications by prioritizing eventual consistency and message isolation over shared-state synchronization.[29][22]
Dynamic Typing and Expressions
E employs dynamic typing, where type information is determined and checked at runtime rather than compile time, allowing variables to hold any object without explicit declarations.[26] This approach, akin to Smalltalk, enables flexible polymorphism and method dispatch based on the actual object type during execution.[28] All values in E are first-class objects, and expressions evaluate to these objects within a lexical scope, producing an outcome that includes a value, an updated scope, or an exception upon failure.[26] Expression semantics in E center on dynamic method lookup, where operators and method invocations resolve to the appropriate implementation on the receiver object at runtime.[32] For instance, arithmetic operators like+ are syntactic sugar for method calls such as left.add(right), permitting operator overloading through custom method definitions on objects, which is particularly useful for capability-based operations like secure reference handling.[26] Evaluation proceeds left-to-right with strict precedence rules, ensuring predictable binding without implicit side effects during computation.[32]
Guards integrate seamlessly with expressions to enforce runtime type assertions and security constraints, often appearing in bindings like def x :guard := expression to coerce or validate the result.[28] These guards, which can specify types such as int or capability facets like near for local references, throw exceptions if the expression's value fails to conform, thereby linking expression evaluation to E's object-capability security model.[26]
E's design supports auditability by promoting the use of pure expressions where possible, facilitating verifiable reasoning about code behavior in distributed and secure contexts, though expressions can include side effects via operators such as assignment (:=) and message sends.[26][28]
Implementations and Usage
Primary Implementations
The primary implementation of the E programming language is E-on-Java, which runs on the Java Virtual Machine (JVM) and compiles E source code directly into Java bytecode, enabling seamless interoperability with Java libraries and applications.[33] This allows E programs to coexist with Java code in the same runtime environment, leveraging the JVM's garbage collection, threading, and distribution capabilities while extending Java with E's object-capability model for secure distributed computing.[2] E-on-Java supports features like distributed garbage collection and robust messaging over networks, making it suitable for building secure, persistent distributed systems.[34] A secondary implementation, E-on-CL, provides an embedding of E within Common Lisp environments, primarily for scripting, rapid prototyping, and experimentation with E's concurrency primitives in a dynamic Lisp runtime.[35] It integrates E's syntax and semantics into Common Lisp, allowing E code to interact with Lisp functions and data structures, though it lacks the full distribution support of E-on-Java and remains in an early stage without official binary releases—the source code is available via a public Git repository.[36] Both implementations are open-source, released under permissive free software licenses compatible with the Mozilla Public License or placed in the public domain for core components, facilitating community contributions and adaptation.[5] Tools for E-on-Java, including the E compiler (ecomp) for bytecode generation, the E Java interpreter (javaec) for runtime execution with E extensions like distributed garbage collection, the ThreadWatcher utility for monitoring concurrency, and the Class Blesser for managing code trust levels, are accessible through downloads and documentation on erights.org.[11][34] E-on-CL relies on Common Lisp tools for development, with no dedicated E-specific binaries provided.[35]Applications and Current Status
E has been applied in domains requiring secure distributed computing, particularly in prototyping systems for electronic commerce and collaborative environments. A canonical example is the mint, a simple yet robust model for secure electronic money implemented using the Electronic Rights Transfer Protocol (ERTP) within E. This system allows for the creation of digital currencies, such as "Joe bucks," through minting authorities that issue purses for holding funds and assays for verifying balances, ensuring tamper-proof transactions via capability-based sealing and unsealing mechanisms.[37] The mint demonstrates how E's object-capability model prevents unauthorized duplication or counterfeiting, supporting inflation-controlled issuance and peer-to-peer transfers in a distributed setting.[37] Beyond financial prototypes, E facilitated the development of distributed applets, extending Java's applet framework to enable secure, network-aware applications like groupware and multimedia systems. These applets leverage E's transparent distribution to communicate across machines while maintaining isolation through capabilities, transforming single-host scripts into collaborative tools without exposing underlying network complexities.[2] Agoric computing, a paradigm for market-oriented distributed systems, finds direct embodiment in E, where objects act as secure rights that can be traded or delegated, underpinning smart contracting mechanisms for decentralized economies.[38] E's design has influenced subsequent languages and concepts in secure distributed systems, notably contributing to the object-capability model adopted in Pony, an actor-model language that combines capabilities with concurrency for safe, high-performance programming.[39] This impact extends to broader ideas in capability-based security, informing secure-by-design architectures in distributed environments, as seen in ongoing discussions of E's promise pipelining for robust concurrency among untrusted parties.[40] As of 2025, E's active development remains limited, with no major language updates since the early 2000s; the last stable implementation, version 0.9.3, addressed bugs and performance but predates widespread modern tooling.[11] Resources remain archived at erights.org, including tutorials, papers, and source code via Subversion, while the community persists through mailing lists like cap-talk, with ongoing discussions including activity in 2025 on topics such as object capabilities and metering,[41] though the e-lang list shows limited posts beyond historical discussions.[42] E's concepts continue to influence contemporary secure systems, such as the OCapN protocol for interoperable capabilities (introduced in 2023) and Agoric's secure JavaScript platforms.[43][44] Despite its foundational contributions, E exhibits gaps in integration with contemporary ecosystems, lacking native support for cloud-native deployments or WebAssembly compilation, which limits its adoption in current scalable, browser-based distributed applications.[1]References
- http://wiki.erights.org/wiki/Main_Page
- http://wiki.erights.org/wiki/Walnut/Secure_Distributed_Computing/E_Capabilities
- http://wiki.erights.org/wiki/Walnut/Ordinary_Programming/Data_Types_and_Control_Flow
- http://wiki.erights.org/wiki/Walnut/Complete
- http://wiki.erights.org/wiki/E-on-CL
