-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Procedural macros interactions with constant evaluation #2279
Comments
AFAIK, D uses the C++ approach to generics (aka "templates"), which is to type-check after monomorphizing them. The macro system is different in that it produces source and must be sequenced before the type-system can exist, for reasons of global reasoning (e.g. Now, for Also, going all the way up to the macro system for an optimization, instead of pushing it down? |
This is base struct for Rust's ndarray pub struct ArrayBase<S, D>
where S: Data
{
/// Rc data when used as view, Uniquely held data when being mutated
data: S,
/// A pointer into the buffer held by data, may point anywhere
/// in its range.
ptr: *mut S::Elem,
/// The size of each axis
dim: D,
/// The element count stride per axis. To be parsed as `isize`.
strides: D,
} #2000 allows to make Assume you have an updated N-dimensional ArrayBase with fixed dimensions at compile time args. In D it would look similar to (very simplified): struct ArrayBase(size_t N, T)
{
...
auto atIndex(Args...)(Args args)
{
enum M = Args.length;
auto ptr = this._ptr;
static foreach (i; 0 .. M)
{
// move ptr to the element/subarray
}
static if (M == N && allIndexes!Args) // allIndexes!Args is a template the evaluates to false/true
{
return *ptr;
}
else
{
enum NewN = ... // compute new N using CTFE and information about types
return ArrayBase!(NewN, T)(*ptr, other_args);
}
}
} #2000 introduces a compilte time constants, but they can not be used to generate/choose code to compile. D's CTFE is something recursive like, it allows to do CTFE, mix code, and do CTFE with mixed code again. #2000 makes me wonder if Rust will be able to do the same |
@9il with specialisation, you can change the implementation based on a constant number without requiring a macro. |
@Diggsey, could you please provide an example? |
Well with both #2000 and specialization, you could do something like this:
|
@9il are you satisfied with the provided solution? if so, please close this issue. :) |
Specialization solve's |
I think looping over tuples should be supplanted by VG (variadic generics). As for looping over integers and using them in const generics, you should be able to do it with a recursive You can probably use specialization to handle And, again, sugar would use generic closures, e.g. |
I'm working on an RFC re. that. :) |
Is there any progress on this? I think this should be revisited due to the recent progress for const generics. For example, now there are some really silly things that rely on this: foo!(u16::from_le_bytes([0x37, 0x13]));
Side question: this is a bit of a weird question, but is const evaluation actually the one single thing that |
I think part of the problem is also that macros expand outside-in but const fn and other code contexts want to evaluate inside-out. |
But const N: u16 = u16::from_le_bytes([0x37, 0x13]);
use_n_in_some_way([24; N]); ... without needing any special cases for |
Well, unless you need the proc-macro to know the value of N as part of the code generation decision. |
That's what I was getting at.
Hm, I didn't realize that. Still, maybe there's some way (maybe an attribute) that a procedural macro could require a const context for its body and also require that the body is pre-evaluated? Also, probably the biggest hurdle in order to do anything useful with the input is that you would need to accept an actual, typed value rather than a token tree, which is really weird. What I'm imagining is basically a normal The more I think about it, the more it sounds like it wouldn't work because type checking, const evaluation, and macro evaluation would be mutually recursive. I only think it might work because Rust can compile things in passes, even across files without forward declaration. One concern is, for example, a const procedural macro relies on |
From 1566-proc-macros.md:
It is terrific feature! It allows to do awesome language idioms such as D's
static if
/static foreach
but in library code.For example
static if
/static foreach
and #2000 are required to port ndslice to Rust from D. I am aware about ndarray cargo package, ndslice implementation has more optimisation powers.Related issues rust-lang/rust#38356
The text was updated successfully, but these errors were encountered: