Format macro question


#1

If you use format! to produce a string from objects, e.g., consts, that are known at compile time, I would think that most – or all – of the work happens at compile time. Am I correct?

Thanks –


#2

I don’t think so - it calls into the formatting machinery at runtime.


#3

That’s too bad.

Do you know of a way to concatenate strings at compile time, some perhaps defined as consts? I’m looking for something analogous to C’s useful feature that “foo”“bar” = “foobar”. Combined with #defines this can be helpful in, for example, building queries with compile-time parameters:

#define LIMIT "10"
char *query = "select * from xyz limit "LIMIT;

I’m guessing there’s a way to do this with Rust macros, but the macro facility is complex and, at least for me, under-documented. I can achieve the effect I want with m4 and a little makefile trickery, but I’d like to know if there’s a way to do this sort of thing in Rust alone.


#4

I’m not sure if there’s a non-macro way to do it - it would require const_fn to allow this level of compile-time eval.

A hacky/quick way to do this (with a simple macro) is:

macro_rules! limit {
    () => {"10"};
}
const QUERY: &'static str = concat!("select * from xyz limit ", limit!());

#5

Thanks. My only issue with that solution is the readability of the code vs using m4, where the query would look like:

define(LIMIT, 10)dnl

const QUERY: &'static str = “select * from xyz limit LIMIT”;

The readability issue becomes more of a problem with actual and much more complex queries.


#6

I’d probably just do:

macro_rules! limit_sql {
    ($sql:tt, $v:expr) => {concat!($sql, " limit ", $v)};
}

const QUERY: &'static str = limit_sql!("select * from xyz", 10);

This is super straightforward (IMO). You can probably get fancier with more sophisticated macros, but I know you’re trying to avoid that.

I don’t know if you’re using a sql query as just an example or not, but if constructing and running sql queries is your actual use case, have you looked at the diesel crate? Here’s a good video by its creator showcasing how they’re able to strip away a lot of the abstraction during sql generation (spoiler: it’s not a compile time constant at the end :slight_smile: ): https://www.youtube.com/watch?v=wxPehGkoNOw


#7

Thanks again. Yes, that’s a nice solution, but I still prefer using m4, because complicated queries are more readable, due to the ability to embed the variables to be replaced directly in the string.

But I will keep this in mind, because this technique can be useful in other situations where readability is less of an issue.