Skip to content
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

Macros by example 2.0 (macro!) #1584

Merged
merged 3 commits into from
Jan 30, 2017
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 148 additions & 0 deletions text/0000-macros.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
- Feature Name: macro_2_0
- Start Date: 2016-04-17
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary
[summary]: #summary

Decalrative macros 2.0. A replacement for `macro_rules!`. This is mostly a
placeholder RFC since many of the issues affecting the new macro system are
(or will be) addressed in other RFCs. This RFC may be expanded at a later date.

Currently in this RFC:

* That we should have a new declarative macro system,
* a new keyword for declaring macros (`macro`).

In other RFCs:

* Naming and modularisation (#1561).

To come in separate RFCs:

* more detailed syntax proposal,
* hygiene improvements,
* more ...

Note this RFC does not involve procedural macros (aka syntax extensions).


# Motivation
[motivation]: #motivation

There are several changes to the declarative macro system which are desirable but
not backwards compatible (See [RFC 1561](https://github.com/rust-lang/rfcs/pull/1561)
for some changes to macro naming and modularisation, I would also like to
propose improvements to hygiene in macros, and some improved syntax).

In order to maintain Rust's backwards compatibility guarantees, we cannot change
the existing system (`macro_rules!`) to accommodate these changes. I therefore
propose a new declarative macro system to live alongside `macro_rules!`.

Example (possible) improvements:

```rust
// Naming (RFC 1561)

fn main() {
a::foo!(...);
}

mod a {
// Macro privacy (TBA)
pub macro foo { ... }
}
```

```rust
// Relative paths (part of hygiene reform, TBA)

mod a {
pub macro foo { ... bar() ... }
fn bar() { ... }
}

fn main() {
a::foo!(...); // Expansion calls a::bar
}
```

```rust
// Syntax (TBA)

macro foo($a: ident) => {
return $a + 1;
}
```

I believe it is extremely important that moving to the new macro system is as
straightforward as possible for both macro users and authors. This must be the
case so that users make the transition to the new system and we are not left
with two systems forever.

A goal of this design is that for macro users, there is no difference in using
the two systems other than how macros are named. For macro authors, most macros
that work in the old system should work in the new system with minimal changes.
Macros which will need some adjustment are those that exploit holes in the
current hygiene system.


# Detailed design
[design]: #detailed-design

There will be a new system of declarative macros using similar syntax and
semantics to the current `macro_rules!` system.

A declarative macro is declared using the `macro` keyword. For example, where a
macro `foo` is declared today as `macro_rules! foo { ... }`, it will be declared
using `macro foo { ... }`. I leave the syntax of the macro body for later
specification.

## Nomencalture

Throughout this RFC, I use 'declarative macro' to refer to a macro declared
using declarative (and domain specific) syntax (such as the current
`macro_rules!` syntax). The 'declarative macros' name is in opposition to
'procedural macros', which are declared as Rust programs. The specific
declarative syntax using pattern matching and templating is often referred to as
'macros by example'.

'Pattern macro' has been suggested as an alterantive for 'declarative macro'.

# Drawbacks
[drawbacks]: #drawbacks

There is a risk that `macro_rules!` is good enough for most users and there is
low adoption of the new system. Possibly worse would be that there is high
adoption but little migration from the old system, leading to us having to
support two systems forever.


# Alternatives
[alternatives]: #alternatives

Make backwards incompatible changes to `macro_rules!`. This is probably a
non-starter due to our stability guarantees. We might be able to make something
work if this was considered desirable.

Limit ourselves to backwards compatible changes to `macro_rules!`. I don't think
this is worthwhile. It's not clear we can make meaningful improvements without
breaking backwards compatibility.

Use `macro!` instead of `macro` (proposed in an earlier version of this RFC).

Don't use a keyword - either make `macro` not a keyword or use a different word
for declarative macros.

Live with the existing system.


# Unresolved questions
[unresolved]: #unresolved-questions

What to do with `macro_rules`? We will need to maintain it at least until `macro`
is stable. Hopefully, we can then deprecate it (some time will be required to
migrate users to the new system). Eventually, I hope we can remove `macro_rules!`.
That will take a long time, and would require a 2.0 version of Rust to strictly
adhere to our stability guarantees.