Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Metaprogramming

Reading

  • The Metaprogramming Dilemma - gingerBill (Odin)

    Defines a list of metaprogramming categories:

    • Introspection (and Reflection for OOP languages)
    • Compile Time Execution (CTE)
    • Template Programming
    • Macros (Textual and Syntactic)
    • Parametric Polymorphism (“Generics”)

    My goal for generics is to have generics obviously, some kind of checked template programming that uses introspection, vm/interpreted compile time execution that is sandboxed and is proven deterministic but can still access things like the heap (Rust const time is way too restrictive, too much hacks)

  • Parametricity, or Comptime is Bonkers

    Though I have not used Zig much, I agree that their comptime are is much free form, and although all abstractions are leaky, it makes it too easy to depend on some construction

    Maybe never allow compiler intrinsic to output information without a trait (except TypeId).

    // has to be the identity because T has no observable properties
    fn foo<T>(foo: T) T {}

    // as opposed to
    fn foo<T: Any>(value: &T) _ {} // we only care about opaque value identity, is used for type maps context in Rust
    fn foo<T: Shape>() _ {} // e.g. shows that it uses T for reflection
    fn foo<T: Layout>() _ {} // layout only gives information for size/alignement
  • facet - GitHub

Samples

How to balance between user power and good ergonomics.

Shape intrinsic

  • Motivation: do not depend on text/token manipulation macros
let shape = Shape::<Directions>::new().variants
// equals: let shape = &[Brush, Line, Rectangle]

Inline statements

  • Motivation: do not depend on text/token manipulation macros
struct Foo { bla: Boo, bar: Baz }

fn deserialize(s: &str) -> T {
let result = Foo::default();
inline for field in Shape::new(result).fields {
field.value = deserialize(s);
}
result
}
inline if std.cfg.host.is_linux() {

} else {

}

Assignment reflection

[..] I very frequently find myself wanting to know the name I’m “about to be assigned to”.

Evelyn Wood, about language design

  • Motivation: in languages where you specify a lot of data inline (e.g. Nix) you tend often have "name" = function("name", { options })

  • Concern: value changes with an LSP rename. Maybe be the source of confusion

  • Concern: makes the expression dependent on context → you cannot extract that expression somewhere else

let kalei = Source::new(`name);
// becomes
let kalei = Source::new("kalei");