# \[Pre-RFC\] Extended dot operator (as possible syntax for \`await\` chaining)

**URL:** <https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304>\
**Category:** language design\
**Created:** [January 29, 2019, 10:44am UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304 "2019-01-29T10:44:06Z")\
**Posts on this page:** 15\
**Page:** 4

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 3, 2019, 6:00pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/61 "2019-02-03T18:00:07Z")

</div>

> [@vorner](#):
>
> They are very well known and tested constructs, everyone needs them in nearly all the code.

That's not true, all of them are different than we known, and all of them can be substituted

> [@vorner](#):
>
> And besides, `?` _did_ start as a macro, to test it out. It worked well, so it got promoted to a full operator.

If I remember correctly, `?` was started as ergonomic improvement over `try!()`, and `try!()` was started as macro without any plan to transform it to `?` (that may be incorrect, through).

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [February 3, 2019, 6:19pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/62 "2019-02-03T18:19:37Z")

</div>

> [@160R](#):
>
> Then why constructs like if, for, ?, try, etc aren’t implemented as macros and not moved into separate libraries? They definitely could be. They are also unnecessary in presence of match/loop/break/return

This is not a valid argument to add more unnecessary cruft to the compiler.

---

<div class="post-metadata">

**Author:** ![samsieber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/samsieber/32/4671_2.png) [@samsieber](https://internals.rust-lang.org/u/samsieber)\
**Post date:** [February 3, 2019, 6:34pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/63 "2019-02-03T18:34:03Z")

</div>

Implementing it as a macro first doesnt prevent it from gaining native support. However, it does let people play with the new syntax / feature.

I’d saying implenting something as a macro increases the chances that it will gain native support. Like the try/? thing.

OTOH, it might also reduce the chance of inclusion if it is something that’d be cause for regret - it makes it easier to see upsides _and downsides_. I think generally a macro implementation (vs no implementation) gives the community more information to work with when deciding to include / exclude a feature.

So here’s my vote for making a macro implementation that can be played around with.

---

<div class="post-metadata">

**Author:** ![Tom-Phinney](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/tom-phinney/32/3299_2.png) [@Tom-Phinney](https://internals.rust-lang.org/u/Tom-Phinney)\
**Post date:** [February 3, 2019, 7:39pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/64 "2019-02-03T19:39:45Z")

</div>

More to the point, if you insist on waiting for language and compiler changes, you’re going to wait for a long time, with progress gated by two overworked teams that already have large backlogs. If you experiment now with a macro implementation, you can proceed at your own pace. Why would you not implement this now as a macro, so that you and others can use it **now**?

---

<div class="post-metadata">

**Author:** ![Pauan](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/pauan/32/3006_2.png) [@Pauan](https://internals.rust-lang.org/u/Pauan)\
**Post date:** [February 3, 2019, 9:49pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/65 "2019-02-03T21:49:45Z")

</div>

I think this feature should be possible to implement with proc macros (even including the `it` magical variable).

Basically, everything inside of the `dot!` can use whatever custom syntax you want:

```rust
dot! {
    let result = client.get("url").[await send()]?.[await json()]?;

    result.[foo()].[bar(it)]
}

```

It might be possible to use [syn](https://crates.io/crates/syn) to parse the code (not sure how it will handle the postfix `[]` though).

I don’t really understand the argument that macros are somehow gross or complex or bad: sure they can be complex to _create_, but they’re not complex to _use_.

Of course you have to go and read the documentation for the macro in order to know how to use it… but that’s also true with functions and ordinary methods!

And learning how to use a macro (such as the above hypothetical `dot!` macro) isn’t any harder than learning new language syntax. Either way you have to learn how to use it.

I agree that this feature is worthwhile, but I think it should be created as a macro first, for experimentation.

---

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 5, 2019, 7:43am UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/66 "2019-02-05T07:43:46Z")

</div>

> [@RustyYato](#):
>
> This is not a valid argument to add more unnecessary cruft to the compiler.

But that's a valid argument that implementing every language feature as macro first is unnecessary.

> [@samsieber](#):
>
> Implementing it as a macro first doesnt prevent it from gaining native support. However, it does let people play with the new syntax / feature.

We already have nightly channel for testing new syntax / features. In this way users would have first class syntax, and there wouldn't be any migration headache. I also would be more ergonomic, so in this form it could attract more users for testing.

> [@Tom-Phinney](#):
>
> More to the point, if you insist on waiting for language and compiler changes, you’re going to wait for a long time, with progress gated by two overworked teams that already have large backlogs.

I can wait as long as it will be required - that's not a problem. I know that the language team is currently busy and that this feature couldn't be in priority in near future. It could be rejected at all - that's fine.

Everything I want currently - to represent this idea as best as possible.

> [@Tom-Phinney](#):
>
> If you experiment now with a macro implementation, you can proceed at your own pace. Why would you not implement this now as a macro, so that you and others can use it **now**?

Probably the most important reason that I don't like macro implementation is that I don't have too much experience with macros and currently I don't know how to implement _exactly_ the same syntax using them:

- how to inject `it` keyword into expression and restrict `it` scope to single level?
- how to return last value depending on presence of comma?

It don't looks trivial, and I don't know what pitfalls here could be. It would require a lot of investigation.

Also, I trying to avoid custom macros when possible and I wouldn't use it in any real world code. For testing purposes it's always enough for me to rewrite some snippet with desired syntax. I fear to promote a macro solution to community because _it easily can create wrong impression_, especially if there wouldn't be any way to provide the same guarantees as in original proposal.

Also, it would be honest to say that I'm not motivated enough for it.

> [@Pauan](#):
>
> I think this feature should be possible to implement with proc macros (even including the `it` magical variable).
> 
> Basically, everything inside of the `dot!` can use whatever custom syntax you want:
> 
> ```rust
> dot! {
> let result = client.get("url").[await send()]?.[await json()]?;
> 
> result.[foo()].[bar(it)]
> }
> 
> ```
> 
> It might be possible to use [syn](https://crates.io/crates/syn) to parse the code (not sure how it will handle the postfix `[]` though).

It don't looks that bad. But it looks more complex than all other macros included in Rust. If someone will implement it as separate crate preserving all properties of this construct - that's ok. However, I don't think that it would be suitable as final solution that should be included into Rust.

> [@Pauan](#):
>
> I don’t really understand the argument that macros are somehow gross or complex or bad: sure they can be complex to _create_ , but they’re not complex to _use_ .
> 
> Of course you have to go and read the documentation for the macro in order to know how to use it… but that’s also true with functions and ordinary methods!
> 
> And learning how to use a macro (such as the above hypothetical `dot!` macro) isn’t any harder than learning new language syntax. Either way you have to learn how to use it.
> 
> I agree that this feature is worthwhile, but I think it should be created as a macro first, for experimentation.

Code with macros is harder to understand. Macros aren't beginner friendly. They have problems with error reporting. They have problems with IDE.

IMO, this macro might will introduce more problems than solve.

---

<div class="post-metadata">

**Author:** ![RustyYato](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/rustyyato/32/13627_2.png) [@RustyYato](https://internals.rust-lang.org/u/RustyYato)\
**Post date:** [February 5, 2019, 3:38pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/67 "2019-02-05T15:38:42Z")

</div>

> [@160R](#):
>
> But that’s a valid argument that implementing every language feature as macro first is unnecessary.

But we don't implement every language feature as a macro, I can only think of 1 that has, `?`. This proposal is simple enough that it can be implemented as a macro, so it should. That way as others have stated, we can see if we need to go further and implement it in the compiler, or if it was a bad decision and deprecate it. As long as it is a macro, we retain some flexibility.

Constructs like `if`, `for`, `try` aren't implemented with macros because with `if` and `for`, there is a long history for how they should work, and they lean make it easier for someone with a background in C or C++ to convert to Rust. This was one of Rust's founding principles. `try` couldn't be implemented as a macro while preserving some important of the features required for them to work well. You could approximate it with this macro:

```rust
macro_rules! try_block {
    ($($block:tt)*) => {
        (
        || {
            $($block)*
        }
        )()
    }
}

```

But you can't you `break` or `return` inside a try block, like you would in the actual try block.

---

<div class="post-metadata">

**Author:** ![nakacristo](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/nakacristo/32/10249_2.png) [@nakacristo](https://internals.rust-lang.org/u/nakacristo)\
**Post date:** [February 5, 2019, 10:06pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/68 "2019-02-05T22:06:35Z")

</div>

For if someone continues to be interested in this feature, I have just implemented a macro for the explicit case using functions (instead of the `it` variable) and using the `=>` symbol. I have used this symbol because it seems that `expr` can only be followed by a few symbols. It is the first macro I have implemented so I may have missed something.

```rust
macro_rules! chain_expand{
    ( $first:expr, $($a:expr,)* @ $($z:expr,)*) => {
        chain_expand!( $($a,)* @ $first, $($z,)* )
    };
    ( @ $first:expr, $($z:expr,)+ ) => {
        $first(chain_expand!( @ $($z,)+ ))
    };
    ( @ $unique:expr,) => {
        $unique
    };
}

macro_rules! chain{
    ( $($a:expr)=>*) => {
        chain_expand!($($a,)* @)
    }
}

fn main() {
    let x=7;
    let y=chain!(x => |t|{t+t+3});
    dbg!(y);
    let z=chain!(x => |t|{t+t+3} => |t|{t*5});
    dbg!(z);
}

```

Also related, I have found the RFC [https://github.com/rust-lang/rfcs/issues/1579](https://github.com/rust-lang/rfcs/issues/1579) about infix notation, which seems very related.

---

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 11, 2019, 7:03pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/69 "2019-02-11T19:03:43Z")

</div>

Anyway, would be it implemented as macro or not - that’s implementation details. If macro wraps the whole parent expression then IMO it’s not too different from plain syntax and discussing it don’t makes too much sense, at least at this point. Currently, I just want to finish design of “pure” functionality and share it with community.

Also, I have thought that RFC should contain “Implementation” section, which would allow to define implementation and functionality details separately, and this would make discussions more focused

---

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 11, 2019, 7:05pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/70 "2019-02-11T19:05:30Z")

</div>

* * *

Meanwhile I’ve done major rewrite of this RFC, where:

- I’ve tried to explain things as best as I can
- `it` was renamed to `this`
- Added “tuple reorganization” use case
- Included new examples
- Described a way how to begin action with external function/binding
- Briefly mentioned alternatives that was provided ITT
- Removed `await` syntax usages as it’s design isn’t decided yet

---

<div class="post-metadata">

**Author:** ![qfire](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/qfire/32/5135_2.png) [@qfire](https://internals.rust-lang.org/u/qfire)\
**Post date:** [February 12, 2019, 4:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/71 "2019-02-12T16:36:52Z")

</div>

FYI, I’ve started implementing the RFC as a macro in the [extdot crate](https://crates.io/crates/extdot).

It’s still a work in progress and missing some things from the RFC and doesn’t incorporate any of the changes you maid yesterday. Also it allows for a few things for testing reasons like allowing `.()` or `.{}` in addition to `.[]`.

The code is also a lot messier than I like but this is the first time I’ve wrote a macro that worked with TokenStream directly since I didn’t find the syn crate very useful when working with new syntax.

---

<div class="post-metadata">

**Author:** ![qfire](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/qfire/32/5135_2.png) [@qfire](https://internals.rust-lang.org/u/qfire)\
**Post date:** [February 12, 2019, 5:36pm UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/72 "2019-02-12T17:36:52Z")

</div>

I did have a few questions that came to mind when implementing the macros:

**Question 1**

```
a.b.[c] ⇒ { let mut _this = a.b ;{ _this.c }}

```

When is this useful? I can’t think of a single instance where this is useful, so for now I implemented the following in the macros:

```
a.b.[c] ⇒ { let mut _this = a.b ;{ c(_this) }}

```

**Question 2**

From RFC:

- _here and below `_this` should be substituted with more unique token_

What is the reason to do a substitution at all? I currently have the macros replacing `this` with `this`. In other words I’m just using the same binding but replacing the `Span` to `Span::call_site()` so it can resolve with rust’s macro hygiene.

**Question 3**

From RFC

1. **Implicit and explicit receiver becomes unavailable inside of nested brace**

This seems to me like it’s trying to enforce subjective style in the parser itself instead of something like `clippy` or `rustfmt`.

---

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 13, 2019, 9:22am UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/73 "2019-02-13T09:22:49Z")

</div>

> [@qfire](#):
>
> **Question 1**

I think that it's better for consistency: you can access methods and field with regular dot and extended dot should support it as well (looks like we also should allow tuple indexing to make it complete). In current way it's also simpler because in order to understand how it works we just need to imagine that reciver "concatenates" with action.

I don't think that resolving `a.b.[c]` to binding or function makes more sense. Binding would be useless, would break consistency, and we would introduce another way of doing things. Resolving it to binding as you suggested would be ergonomic, but I think it's still problematic:

1. Breaks consistency
2. Don't looks as method calling at all
3. Don't uses explicit `this` when we call external function
4. Looks very close to array indexing (it's not a problem in current RFC because warning would be issued on such snippets)

> [@qfire](#):
>
> **Question 2**

When implementing extended dot as macro probably it really don't makes sense. But there's reason when implementing it as language construct. I admit that currently this reason isn't obvious at all and the next update to this RFC should clarify it.

> [@qfire](#):
>
> **Question 3**

IMO extended dot syntax should remain declarative as the whole method call chain is declarative. Bindings are more appropriate for imperative programming. And I currently even don't see any use case where using `this` inside of braces would make any sense.

---

<div class="post-metadata">

**Author:** ![160R](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/160r/32/9502_2.png) [@160R](https://internals.rust-lang.org/u/160R)\
**Post date:** [February 14, 2019, 6:47am UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/74 "2019-02-14T06:47:42Z")

</div>

New updates:

1. To make it simpler, embedding language constructs into chain now requires explicit `this`, e.g. `vec.[!this.is_empty()]`
2. All dot properties (method, field, tuple indexing) should be supported by implicit `this`
3. Rewritten desugaring section; now it could be seen how replacing of `this` with unique identifier invalidates `this` in nested braces
4. Changed other descriptions

---

<div class="post-metadata">

**Author:** ![system](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/system/32/14092_2.png) [@system](https://internals.rust-lang.org/u/system)\
**Post date:** [May 15, 2019, 6:47am UTC](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304/75 "2019-05-15T06:47:44Z")

</div>

Closed on May 15, 2019, 6:47am UTC

This topic was automatically closed 90 days after the last reply. New replies are no longer allowed.

[Previous page](https://internals.rust-lang.org/t/pre-rfc-extended-dot-operator-as-possible-syntax-for-await-chaining/9304.md?page=3)
