ADM Bot

Programming Language

One language for apps,
services, and interfaces.

ADM is statically typed and compiles to native binaries. Contracts, transactions, background services, and UI components are part of the language - not libraries you bolt on.

launch.adm
module rocket {
	use std.units::*

	// Contracts: checked when the function starts and when it returns.
	def burnTime(fuel Mass, rate MassFlow) !Time {
		expects {
			assert rate > 0 onerror fail "engine off"
		}
		let t = fuel / rate
		return t
		provides {
			assert t < 10(min) onerror fail "burn too long: {t.str(min)}"
		}
	}

	// Compiled for the GPU; runs on the CPU when there is none.
	cuda def cool(temps float64[], by float64) !none {
		int i = blockIdx.x * blockDim.x + threadIdx.x;
		if (i < temps_len) temps[i] -= by;
	}

	async def weather() string {
		use std.net.http
		let reply = http.get("https://wttr.in/Cape+Canaveral?format=3") onerror return "no go"
		return reply.text() onerror recover "no go"
	}

	async def range() string {
		return "go"
	}
}

application Launch {
	use (
		std.units::*
		rocket
	)

	let fuel Mass = 0

	def load(m Mass) {
		begin { fuel += m }
		rollback { fuel -= m }
	}

	// When anything inside fails, every rollback runs.
	def fuelUp(m Mass) !none {
		transaction {
			load(m)
			let t = try rocket.burnTime(fuel, 2.5(t/s))
			println("burn for {t.str(s)}")
		} onerror (err error) {
			println("scrubbed: {err.message}, fuel back to {fuel.str(t)}")
			recover none
		}
		return none
	}

	def new(args string[]) int {
		fuelUp(2000(t)) onerror return 1
		fuelUp(400(t)) onerror return 1

		// Both checks run at once; the first answer wins.
		let status = await (rocket.weather() || rocket.range())
		println("status: {status}")

		// All four engines compared in one SIMD instruction.
		let temps = float64[910.0, 870.0, 1020.0, 880.0]
		let v vec4<float64>
		let hot = v.load(temps, 0).gt(v.splat(1000.0))
		if hot.any() {
			rocket.cool(temps, 50.0) onerror recover none
		}

		// One task per engine, spread across cores, reporting on a channel.
		let telemetry channel<string> = new(size = 4)
		forall let (i, t) in temps {
			telemetry <- "engine {i}: {int(t)} K"
		}
		telemetry.close()
		for let line in telemetry {
			println(line)
		}
		return 0
	}
}

What's in the box

Structured

Structs, enums, unions, interfaces, and datatypes for describing data. A type satisfies an interface or datatype by having the right members, with no implements clause.

Expressive

Pattern matching, string interpolation, async/await, and channels. Errors are values: !T to return one, try to pass it up, onerror to handle it.

Native

Compiles ahead of time for Linux, macOS, Windows, Android, iOS, and WASM. SIMD vectors are built into the language, and a cuda def function runs on the GPU.

Units of measure

Numbers can carry units: 100(km), 9.81(m/s²). Distance divided by time gives a speed, which you can print in km/h, m/s or any other speed unit. Over 700 units are built in, counting prefixed forms like km and MiB.

Batteries included

The standard library is written in ADM: networking, cryptography, compression, and codecs for many file formats (images, audio, video, fonts, documents, archives, mail).

Permissions

Control what each program and each library can access (files, the network, devices) through permissions and policies. You see what a library needs before you add it, and the user decides what the app gets when it runs.

Download

ADM ships as a single self-contained package: the compiler, the standard library and a bundled C toolchain. The standard library still has gaps; read the docs or browse the examples to see where it's heading.

Install with one command (current user, no sudo):

curl -fsSL https://raw.githubusercontent.com/admlang/adm/main/install.sh | sh

Installs into ~/.adm and adds ~/.adm/bin to your PATH. Later, adm update fetches new releases. Prefer to do it by hand? Grab the adm-<version>-linux-amd64.tar.gz from the latest release, unpack it anywhere and put its bin/ on PATH. The IntelliJ plugin is on the same page.