This test evaluates a language's metaprogramming capabilities by examining whether advanced runtime introspection and code manipulation can be implemented as libraries, without requiring compiler plugins or built-in language features.
Open your P/Rs. Isolated examples are preferred over links to external libraries.
Can the language implement a structured logger as a library, without compiler plugins or macros?
When we write logger.log(s"Hello ${user}, your balance is ${balance}"), the program should automatically extract both the template and variable values, printing JSON like:
{
"template": "Hello %user%, your balance is %balance%",
"args": {
"user": "John",
"balance": 42
}
}A perfect implementation should not fail if it meets a function argument of unexpected shape (e.g. a call to another function).
Can we implement reflection as a library without relying on native language capabilities?
Our reflection library should support:
TypeId[T]withis_same[A, B](id1: TypeId[A], id2: TypeId[B])operation for run-time type identity comparison.- Operation
is_subtype_of[A, B](child: TypeId[A], parent: TypeId[B])for run-time subtype checking (in languages with subtyping)
Can the language implement a concept called Functoid?
A Functoid turns an arbitrary function into a runtime-introspectable entity that can:
- Invoke the original function with dynamically-provided arguments
- Retrieve type tags for each parameter
Can we attach custom identifiers to each parameter's type tag?
Rust Example:
#[functoid]
fn greet(#[id("user-name")] name: String, #[id("msg")] msg: String) -> String {
format!("{}, {}", msg, name)
}Scala Example:
val funcFunctoid: Functoid[Int => String] = Functoid {
(prefix: String @Id("prefix")) =>
(n: Int) => s"$prefix-$n"
}Kotlin Example:
fun createService(
@Id("primary") db: Database,
@Id("cache") cache: Cache
): Service {
return Service(db, cache)
}
val functoid = FunctoidFactory.fromFunction(::createService)
// Automatically extracts type tags with @Id annotations
functoid.getParameterTypes().forEach { tag ->
println("${tag.type} @Id(\"${tag.id}\")")
}We would like to see if the following can be done:
- Structural logger with automatic argument name extraction
- Robust structural logger with automatic argument name extraction which won't fail on unexpected argument shapes (e.g. a function call or some expression passed as an argument)
- Run-time comparable
TypeId[T]using compiler intrinsics, standard library or runtime features - Run-time comparable
TypeId[T]implementable fully as a library (pure) - Run-time
is_subtype(TypeId[A], TypeId[B])operation using compiler intrinsics, standard library or runtime features - Run-time
is_subtype(TypeId[A], TypeId[B])operation implementable fully as a library (pure) FunctoidimplementationFunctoidimplementation which supports named arguments
| Language | 1. Logger | 2. Logger (robust) | 3. TypeId (w/ RT) | 4. TypeId (pure) | 5. Subtype (w/ RT) | 6. Subtype (pure) | 7. Functoid | 8. Functoid (@Id) |
|---|---|---|---|---|---|---|---|---|
| Scala | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
| Python | ✅ | ✅ | ✅ | ➖ | ✅ | ➖ | ✅ | ✅ |
| C++ | ✅ | ✅ | ✅ | ✅ | ✅ | ❌ | ||
| Rust | ✅ | ✅ | ✅ | ❌ | ❌ | ❌ | ✅ | ✅ |
| Haskell | ✅ | ❓ | ✅ | ❓ | ➖ | ➖ | ✅ | |
| Zig | ✅ | ✅ | ✅ | ❌ | ➖ | ➖ | ✅ | |
| Swift | ✅ | ✅ | ❌ | ✅ | ||||
| Kotlin | ❌ | ❌ | ✅ | ❌ | ✅ | ❌ | ✅ | ✅ |
| TypeScript | ❌ | ❌ | ➖ | ➖ | ❌ |
Legend:
- ✅ - Complete working implementation
⚠️ - Partial implementation (relies on conventions, has limitations, or uses workarounds)- ❓ - Implementation possible and pending
- ➖ - Not applicable
- ❌ - Likely impossible to implement
- Links point to implementation directories
Notes:
- Scala: Reference implementation (all features via izumi ecosystem)
- Kotlin: Native reflection for TypeId and subtyping; Functoid with @Id annotations
- Python: Frame introspection for logging; runtime reflection TypeId via type();
@idthroughAnnotated - Rust: Macros for logging; TypeId via std::any::TypeId; Functoid with #[id] attrs
- TypeScript: Convention-based Functoid with compile-time metadata enforcement
- Haskell: Template Haskell for basic variable capture (robust logger impossible - would require parsing Haskell syntax from strings); Typeable/Type.Reflection for runtime type identity; GADTs with type-level strings for functoids (parameter IDs via type-level strings, not annotations).
- C++: Structured logging includes robust variant (
LOG_ROBUST) that handles arbitrary expressions using preprocessor stringification with try-catch fallback. All three challenges implemented using C++20 template metaprogramming, constexpr evaluation, and compiler intrinsics. - Zig: Comptime execution for all challenges;
@typeName()for pure library TypeId;@typeInfo()for complete function introspection; struct-based named parameters for logging (requires explicit field names like.{ .user = user, .balance = balance }as Zig doesn't preserve variable names in tuple arguments); parameter IDs via compile-time arrays or runtime assignment. - Swift: Mirror API for runtime reflection; KeyValuePairs or struct-based logging; TypeId via type name comparison; subtype checking only on macOS/iOS via ObjectiveC runtime; Functoid with manual parameter names (closures don't preserve parameter names at runtime).
Scala (izumi ecosystem):
- Structured Logging: LogStage
- Type Reflection: izumi-reflect
- Functoid: distage
Python:
- Functoid: Chibi Izumi
TypeScript:
- Functoid: Chibi Izumi (partial)
| Language | Run-time Type Id | Run-time Subtype check |
|---|---|---|
| Scala | ❌ |
❌ |
| Rust | ✅ TypeId | ❌ |
| Haskell | ✅ Typeable | ➖ |
| Kotlin | ✅ KClass | ✅ Reflection |
| Python | ||
| TypeScript | ❌ | ❌ |
| C++ | ||
| Zig | ✅ @typeInfo | ❌ |
| Swift | ✅ Mirror | ✅ Type Casting |
| Language | Macros/CSE |
|---|---|
| Scala | ✅ AST-level |
| Rust | |
| Haskell | ✅ Template Haskell |
| Kotlin | ❌ |
| Python | |
| TypeScript | ❌ |
| C++ | |
| Zig | ✅ comptime |
| Swift |
| Language | Interface w/dynamic dispatch | Interface w/static dispatch |
|---|---|---|
| Scala | ✅ Traits | ✅ Implicits |
| Rust | ✅ Trait objects | ✅ Traits |
| Haskell | ➖ | ✅ Typeclasses |
| Kotlin | ✅ Interfaces | ❌ |
| Python | ✅ ABC/Protocol | ➖ |
| TypeScript | ❌ | |
| C++ | ✅ Virtual | ✅ CRTP |
| Zig | ✅ comptime | |
| Swift | ✅ Protocols | ✅ Witness tables |
| Language | HKT | Incoherent Typeclasses | Coherent Typeclasses | Implicits | Do-notation |
|---|---|---|---|---|---|
| Scala | ✅ Kind polymorphism | ✅ Implicits | ❌ | ✅ Implicits | ✅ |
| Rust | ❌ | ❌ Orphan rules | ✅ Trait coherence | ❌ | ❌ |
| Haskell | ✅ Kind system | ✅ Default | ❌ | ✅ | |
| Kotlin | ❌ | ❌ | ❌ | ❌ | |
| Python | ❌ | ❌ | ❌ | ❌ | |
| TypeScript | ❌ | ❌ | ❌ | ||
| C++ | ❌ | ❌ | |||
| Zig | ❌ | ❌ | ❌ | ❌ | |
| Swift | ❌ | ❌ | ❌ |