Skip to content

E#

A modern, composable, object-oriented language for the .NET CLR. Readable like Go, native to the runtime like C#, and a fraction of the surface area.

The E# programming language is a general-purpose language that compiles to standard .NET assemblies — the same Common Language Runtime (CLR) that runs C# and F#. A .es file becomes a .dll that any C# project can reference without knowing it wasn’t C#. The file extension is .es. It is not ECMAScript, and it is not a dialect of C# — it’s its own language that happens to share the .NET runtime.

namespace Demo
// `data` is a value type: copied on assignment, compared by its fields,
// no heap and no identity unless you ask for them.
data Money { amount: int, currency: string }
// A `choice` is a tagged union — the set of things that can happen, as data.
choice ParseError {
empty
badNumber(text: string)
}
// Errors are values. `Result<T, E>` and `?`, not exceptions.
func parse(s: string) -> Result<Money, ParseError> {
if s.Length == 0 { return error(.empty) }
var n = 0
if !int.TryParse(s, out n) { return error(.badNumber(s)) } // BCL interop is direct
return ok(Money { amount: n, currency: "USD" })
}
// A free function whose first parameter is `Money` *attaches* to it as a method.
func describe(m: Money) -> string = "{m.amount} {m.currency}"

E# came from wanting a particular language the CLR didn’t have: a type system that reads like Go but goes further — generics, classes when you need them, and ideas borrowed from Rust (tagged unions you match exhaustively, errors as values, the -> return syntax). Concurrency shaped by Go and Swift. An object model that sits between Go and C#: more structure than Go, less ceremony than C#.

Because being a first-class CLR citizen was a goal from the start, E# also does something .NET never really had — .es and .cs files fuse into a single assembly, so you can drop it into a corner of an existing C# codebase and keep going. That’s the JVM’s in-project polyglot story, finally on the CLR, and it was an early focus because it falls straight out of being native to the runtime.

The aim isn’t more features than C#; it’s fewer, composed well: value types by default, errors as values, uncolored async, methods that attach to types instead of being trapped inside them.

Native to the CLR

Compiles through Mono.Cecil to ordinary IL. E# types are indistinguishable from C# types to a consumer — reference the .dll and call them. Interop →

Value-first

data is value-semantic; ref data is the opt-in object world. The CLR form (struct or class) is the compiler’s call. Types →

Errors as values

Result<T, E> and ? propagation for in-language flow; try/catch only at the BCL boundary. Errors →

Uncolored async

Any await promotes its function — no async keyword. Uncolored by default; semi-colored when you want it, since the return type picks the machinery. Concurrency →

E# is general-purpose — it covers the same ground as any other CLR language, with no single intended niche. Because .es and .cs compile into a single assembly, it can be added to an existing C# project incrementally, a file at a time, as readily as it stands on its own.

It is pre-alpha. The IL compiler is the source of truth and runs every emitted assembly through ILVerify; the language is real and tested, but the surface is still moving. The corpus is a large set of real .es programs drawn from the language’s own test suite and samples — passing test cases, showcases, and integration tests — each one compiled cleanly (or rejected with its expected diagnostic) and either producing its asserted output or standing as a real, well-formed program. It’s the most honest picture of what compiles today.


The name: E# is the major third above C# — a sibling in the same key. It was available. No deeper claim than that.