Will the Rust developers do something about macros?

Will the Rust developers do something about macros? To fix them somehow, it is possible to add comptimes.
There is a post on Reddit, but it is not clear what will happen to macros.

What do you want changed about macros?

I want macros to be clear and easy to learn. Or comptimes :smiling_face_with_tear:

What do you mean by "comptimes"? Faster compile times?

Comptime that is in Zig

The question has a positive note, without negativity. I would like to discuss what prospects there are in this direction.

From looking into comptime in Zig, it seems the corresponding feature in Rust would be const: const blocks for forcing compile-time evaluation (not needed in the initializer of const and static items, which are always evaluated at compile time), and const generics for compile-time parameters. The one difference from Zig's comptime seems to be that Zig doesn't require functions to be marked as usable with it, whereas Rust requires functions to be marked as const to use them in const contexts (this allows changing the function body without changing where it can be used, and separates the checking of a function's const compatibility from where it is used).

2 Likes

When people talk about comptime they really talk about Zig's implementation of reflection and compile-time code generation.

Technically, in Zig, comptime function is close to const fn in Rust (or, even closer, to immediate function in C++).

But the trick that Zig employes, literally, everywhere, is the fact that these functions, because they are executed during compilation, can accept and return types and function bodies (in Rust, I guess, they would have to also accept and return traits).

It's really cool way of doing metaprogramming, much more flexible and argonomic that Rust's macros.

And, of course, Zig implements generics, async and other things using that approach, too.

The usual retort on Rust side is that comptime makes it impossible to do the type of analysis that compiler can do to traits… but that only makes sense when comptime is considered as replacement to generics.

When we are talking about macros… comptime is much easier to use on may levels – although macros have advantages, too: you can do cargo expand and get decent approximation of what is actually processed… with comptime that's not really possible.

14 Likes

A tangent: I think that there’s a more general missing tool / unsolved problem here. Not to do with macros vs. comptime, but the general principle that (in certain types of situations) it’s harder to inspect some “thing” when the thing is “the behavior of some code” rather than “some data”.

For another example, suppose your program A is manipulating a library data structure B, which then misbehaves or ends up in the wrong state. You want to file a bug report with B, but it should be minimal and clear, not bringing in the specifics of “what program A is doing”. It would be useful if there was some automatic way to, given a specified boundary between A and B, record everything that is done to B, and produce a new program of straight-line code that does the same sequence of operations to B.

This requires a lot of reflection capability to implement, but if it existed, it would be, in a way, the equivalent of macro-expanding non-macros: automatically replacing an algorithm with its output.

(Of course, there are cases where such an automatically generated “script” would itself be illegible, or fragile due to run-time nondeterminism.)

4 Likes

Another method of doing this kind of meta-programming in rust is a build script.

You can run arbitrary rust code before compiling your src code. The output of which can be more src code that gets compiled (I think!). It lacks the ergonomics of comptime, a. because you are dealing with strings that happen to become code structures once compiled, and b. because it's tucked away in a separate file and would really struggle to insert stuff in situ amongst the rest of your source code.

In principle, I suppose there's nothing stopping you from parsing your source code using syn and manipulating it to create more source code. But you're left to your own devices once you step outside of rust's macro system.

I admire Zig's comptime capabilities, I think they provide an awesome amount of flexibility. Rust has other strengths

I've recently posted in a similar thread on Zulip, about how I think Rust should strive to make it's non-proc macros more like Crystal. It would be a huge improvement in ergonomics, while being way less drastic of a change than types-as-values and Zig-style comptime.

1 Like

I just went through a bender to write some rust macros. The error messaging of macros is just horrible. I ended up with doing a lot of

cargo expand

and adding horrible things like

 let output_str = quote!{
   // your quote here
 }.to_string();
 return quote! {
     compile_error!(#output_str);
 }

But even then writing my derive macro was much more difficult than I'm used to with the rest of rust's error messages.

This is practically what derive and attribute-style proc-macros do. The issue is that it operates at the level of AST tokens. There is zero information available from the type system at this level.

A lot can be done without type info, regardless. And it's far better than working with the declarative macro_rules DSL. But improvements would be welcomed.

3 Likes

Introwospection was a great attempt to shift the status quo, but, unfortunately, it didn't go well due to untechnicall reasons.

1 Like

The main advantage of TMP and comptime is the fact that you can ignore combinations of things that are useless for you.

The main disadvantage of TMP and comptime is the fact that you can ignore combinations of things that are useless for you.

That's very hard to handle with macros or build scripts.

If you'll think about it… generics and templates are like thiserror vs anyhow: handle all cases precisely vs let the developer sort out the mess.

Yet with error handling people accept the fact that there are two valid approaches, but with generic programming everyone have an opinion and assert that only one or the other is “valid”.

4 Likes

rust does have planned features for constant blocks that evaluate to const generics... perhaps we could extend that to having const blocks that evaluate to type generics?

this would basically give use the power of zig comptime, and it would do it without making it a disparate thing from rust's existing generics.