Type System
The C! type system is the foundation of its security guarantees. It combines linear types, affine types, refined types, and sum types to eliminate entire classes of bugs at compile time.
Linear Types
A linear type must be used exactly once. This is the core mechanism that prevents double-spend, use-after-free, and resource leaks. When a value of a linear type is consumed (passed to a function, moved into a structure), it cannot be used again.
// Token is a linear type — must be used exactly once fn transfer(token: own Token, to: Address) -> Receipt { ledger.move(token, to) // token consumed here } fn example() { let t = mint_token(); transfer(t, alice); // OK: t is consumed transfer(t, bob); // COMPILE ERROR: t already consumed }
The compiler tracks ownership of every linear value through every code path, including branches and loops. Forgetting to use a linear value is also a compile error, preventing resource leaks.
Affine Types
An affine type can be used at most once. Unlike linear types, it is safe to drop an affine value without using it. This is useful for optional cleanup or cancellation tokens.
// CancelToken is affine — use at most once fn start_task() -> borrow CancelToken { let cancel = spawn_background_work(); return cancel // caller may or may not use it }
Refined Types
Refined types carry constraints as part of the type itself. A String{len: 1..100} is not just a string — it is provably between 1 and 100 characters. The compiler enforces these constraints.
type User { name: String{len: 1..100}, age: u8{range: 0..150}, email: Email, // built-in validated type }
Sum Types
Sum types (also known as tagged unions or algebraic data types) let you define a type that can be one of several variants. The compiler ensures you handle all variants, eliminating null pointer errors and unhandled cases.
type Result<T, E> = Ok(T) | Err(E) fn process(r: Result<User, DbError>) { match r { Ok(user) => greet(user), Err(err) => log_error(err), } // exhaustive — missing a case is a compile error }
Intent Annotations
Intent annotations are structured metadata that describe what a function should do, not how. They serve a dual purpose: they allow any AI to instantly understand the codebase, and they allow the compiler to formally verify correctness.
#[intent("Transfer tokens between accounts, ensuring sender has sufficient balance, atomic — both sides update or neither does")] #[invariant(total_supply_unchanged)] #[pre(balances[from] >= amount)] #[post(balances[to] == old(balances[to]) + amount)] fn transfer( from: Address, to: Address, amount: u256 ) { // Implementation verified against annotations }
AI Workflow: An AI agent reads the #[intent(...)] annotation, generates the function body, and the compiler verifies the implementation satisfies all #[pre], #[post], and #[invariant] conditions. If it compiles, the AI got it right.
Actor Model
C! uses the actor model for concurrency. Each actor owns its state exclusively, and communication happens through typed messages. There is no shared mutable state, making data races impossible by construction.
actor Counter { state count: u64 = 0 on Increment(by: u64) { count += by; reply count } on GetCount { reply count } } // Supervision tree for fault tolerance supervisor AppSupervisor { strategy: OneForOne, children: [Counter, Logger, Cache] }
Deployment Targets
C! compiles a single codebase to multiple targets without code changes:
- Native binaries — High-performance executables for servers and CLI tools
- WebAssembly (WASM) — Run in browsers and edge environments with near-native speed
- Blockchain bytecode — Deploy smart contracts to EVM-compatible chains
Full-stack shared types: Your User type defined once is used identically in your backend API handler, your frontend WASM component, and your on-chain contract. No serialization bugs, no schema drift.
Smart Contracts
C! treats smart contracts as first-class citizens. The linear type system makes reentrancy attacks impossible by construction — once state is consumed in a transaction, it cannot be accessed again until the transaction completes.
#[contract(evm)] actor Vault { state balances: Map<Address, u256> #[payable] on Deposit() { balances[msg.sender] += msg.value; } on Withdraw(amount: u256) { verify!(balances[msg.sender] >= amount); balances[msg.sender] -= amount; // State updated BEFORE external call // Reentrancy impossible: state is linear send(msg.sender, amount); } }
Standard Library
The C! standard library provides core types and utilities, all built on the linear type system:
| Module | Description |
|---|---|
std::collections |
Vec, Map, Set with ownership-aware APIs |
std::io |
File, network, and stream I/O with linear handles |
std::crypto |
Hashing, signing, verification primitives |
std::net |
HTTP client/server, WebSocket, gRPC |
std::json |
Type-safe JSON serialization/deserialization |
std::test |
Testing framework with property-based testing |
std::async |
Async runtime built on the actor model |