jakt
jakt copied to clipboard
Static Reflection
It would be super nice to support this as it remains a major pain point of C++ (at least for myself); introspection of types being the main desired feature
- the keyword
reflect
- an expression of the form
reflect type-name
- Implementation requirements:
- Should present a meaningful interface to the user, perhaps through predeclared types
- Should work with generic types
- Should have all the information to reconstruct the reflected type (though not required for basic functionality)
small example (syntax is made-up and not decided)
enum Foo<T> {
Var0: T
Var1: i32
}
function foo() -> String {
return match reflect Foo {
Enum(variants: vs) {
vs.first().name
}
_ => verify_not_reached()
}
}
Instead of introducing a new keyword, why not do what Zig does and treat types like objects of type Type? Type would act like a compile time struct with some fields like name and an enum of enum, class, struct, function, etc. And each of those would have fields that describe them. So, for function the API would look like:
struct Function {
name: String,
arguments: Array<Variable>,
return_type: Type,
block: Array<Statement> // Maybe.
}
And it would be used like:
function foo() {
return match foo.type {
Function(function: f) => f.name + " returns " + f.return_type.name
// ...
}
}
And for enum:
enum BetterOptional<T> {
Some(T)
None
}
function bar() {
return match BetterOptional.type {
Enum(variants: vs) => vs[0].name // If indexing past Array, throw error at compile time.
// ...
}
}
Not exactly sure what the expected behavior would be when taking the name of a templated type, so maybe it would only be valid if either the type has its templates filled out or you don't touch T
.
I'm fairly against pretending that typenames are values, we don't have type-level computations, and we don't have kinds, so T
wouldn't actually be a "type", it'd have to be magically reflected if you name it as an expression
instead of implicitly doing so, we can keep the parser simpler with a keyword and call it good.
note that my suggestion doesn't place compile-time execution restrictions, reflect(T)
is a runtime value.
Slowly moving, but I've got a partial implementation working in https://github.com/alimpfard/jakt/tree/sr. With the CTFE support present, it's relatively simple to do - just need some time to support enough to be useful.