I'm curious what are these other languages that can do these things? I read HN regularly but don't recall them. Or maybe that's including things like Java's annotation processing which is so clunky that I wouldn't classify them to be equivalent.
I'm curious what are these other languages that can do these things? I read HN regularly but don't recall them. Or maybe that's including things like Java's annotation processing which is so clunky that I wouldn't classify them to be equivalent.
It’s beautiful to implement an incredibly fast serde in like 10 lines without requiring other devs to annotate their packages.
I wouldn’t include Rust on that list if we’re speaking of compile time and compile time type abilities.
Last time I tried it Rust’s const expression system is pretty limited. Rust’s macro system likewise is also very weak.
Primarily you can only get type info by directly passing the type definition to a macro, which is how derive and all work.
How so? Rust procedural macros operate on token stream level while being able to tap into the parser, so I struggle to think of what they can't do, aside from limitations on the syntax of the macro.
If you have a derive macro for
#[derive(MyTrait)]
struct Foo {
bar: Bar,
baz: Baz,
}
then your macro can see that it references Bar and Baz, but it can't know anything about how those types are defined. Usually, the way to get around it is to define some trait on both Bar and Baz, which your Foo struct depends on, but that still only gives you access to that information at runtime, not when evaluating your macro.Another case would be something like
#[my_macro]
fn do_stuff() -> Bar {
let x = foo();
x.bar()
}
Your macro would be able to see that you call the functions foo() and Something::bar(), but it wouldn't have the context to know the type of x.And even if you did have the context to be able to see the scope, you probably still aren't going to reimplement rustc's type inference rules just for your one macro.
Scala (for example) is different: any AST node is tagged with its corresponding type that you can just ask for, along with any context to expand on that (what fields does it have? does it implement this supertype? are there any relevant implicit conversions in scope?). There are both up- and downsides to that (personally, I do quite like the locality that Rust macros enforce, for example), but Rust macros are unquestionably weaker.