// E# — a verified example from the E# language corpus (CLR language; .es, not ECMAScript). // provenance: delegates_and_pointers.es topic: delegates-events status: verified // hand-authored, idiomatic E# — verified through the E# compiler namespace Demo // ═════════════════════════════════════════════════════════════════════════════ // Passing behavior as a value: E# has three callable forms, chosen by intent. // // 1. Function pointer — `&func`, type `&(int, int -> int)`. Zero allocation, no GC: // `ldftn` + `calli`. The systems tier — hot paths, dispatch tables. (C# needs // `unsafe` + `delegate*` for this; E# makes it safe by construction.) // 2. Nominal delegate — `delegate func Name(...)`. A named `MulticastDelegate` type, // distinct from any structurally-identical delegate. Intent-named, interop-friendly. // 3. BCL delegate — `Func<...>` / `Action<...>`. Structural, heap, multicast. The // framework-callback tier. // // A bare function name converts to whichever delegate type is expected (method-group // conversion), and a lambda's parameter types are inferred from the target. // ═════════════════════════════════════════════════════════════════════════════ // (2) A NOMINAL delegate type. `BinOp` is its own type — a `Func` is NOT a // `BinOp`, even though both wrap (int, int) -> int. delegate func BinOp(a: int, b: int) -> int func add(a: int, b: int) -> int = a + b func mul(a: int, b: int) -> int = a * b // Parameter typed as the nominal delegate. A bare `add` passed here converts (method group). func apply(op: BinOp, a: int, b: int) -> int = op(a, b) // Parameter typed as a BCL `Func`. A lambda converts, its `x` inferred as int. func applyFunc(f: Func, x: int) -> int = f(x) // Parameter typed as a function POINTER. `&name` takes the address; the call is a `calli`, // with no delegate object allocated. func applyPtr(f: &(int, int -> int), a: int, b: int) -> int = f(a, b) func main() -> int { let viaDelegate = apply(add, 3, 4) // 7 — method group → nominal delegate let viaLambda = applyFunc((x) => x * 2, 10) // 20 — lambda → Func let viaPointer = applyPtr(&mul, 5, 6) // 30 — &mul → ldftn + calli, zero alloc return viaDelegate + viaLambda + viaPointer // 57 }