The idea of making them part of method dispatch, such that they depend on the type of the LHS, would be a much more complicated proposition, because we generally need to fully resolve macros before we have enough information for type dispatch. It's possible to solve that, and there are research languages that solve that, but it'd be a much harder problem.
The approach I used in RFC 2442 was instead to not care about types, just as existing macros don't care about types. (That still leaves room in the future for macros that care about types, whether postfix macros or regular macros.)
Can you say which properties of macros you're interested in here? Do you really want to do macro-like things in them (which depend on the passed-in tokens, or do caller-control-flow-affecting things), or are you just trying to value-like things without needing to write types?
It doesn't help that you appear to never use $z so I don't know what you mean by it.
the aspect that appeals to me the most is being able to define a DSL-y custom syntax. i'm using macro_rules! for this example but ideally a proc macro would also be possible... somehow. i don't think the whole "proc macros need to be in a seperate crate" works well with being in the middle of an impl block, but i don't have any good ideas atm
consequentially this is interesting in its own right but not precisely the same as what i'm suggesting
I don't think that's a very good motivating example. I'd help if you were able to provide an example where you really want dsl syntax in a method call.
I'm gonna go ahead and say that the standard matches! macro would be really neat as a postfix macro: a.matches!(Some(Ok(1))).
Adding method scoping to a specific type seems like it'd require a pretty dramatic amount of changes to the compiler, for seemingly very little benefit.
We can have a separate macro role, called like expression macro that consumes the whole expression token chain prior to its invocation and the arguments to produce token chain that matches expr. -> so that a.method().call!(argument).other_method() is equvivalent to call!(a.method(),argument).other_method()
it can result in confusing behavior when the macro doesn't use the $self argument exactly once, because that part is syntactically not inside the macro, but is still affected by it.
a.field
.method(argfunc())
.maybenot!()
could possibly not call method or even argfunc(), without an obvious syntactic marker of that happening.
the macro would have to be resolved based on the type of the receiver, which may run into type checking issues (macros are currently expanded before types are checked)
mod a {
pub struct A;
impl A {
macro_rules! bad {
($self) => {
use b::A;
}
}
}
}
mod b {
pub struct A;
impl A {
macro_rules! bad {
($self) => {
use a::A;
}
}
}
}
use a::A;
fn main() {
A.bad!(); // What is A here?
}
This can probably be fixed, but it is far from trivial to do.
Instead, what I think would be more feasible:
Make method macro resolution independent of receiver type -- use normal name resolution instead.
This avoids issue #2, but comes with these limitations:
method macros have to declared outside of impl blocks, "polluting" the namespace more than they should (because Rust does not have a global namespace, this is less of an issue)
method macros can not be "overloaded" based on receiver type
Evaluate the receiver expression exactly once regardless of the macro. Bind its result to an unnameable temporary variable. Make the $self argument of the macro refer to that variable.
This would fix issue #1.
this does not allow the macro to inspect or modify the receiver expression.
I'm not sure what scope the temporary variable should have -- is it ok if it has normal variable scope or should it have some Special Scope™?