# \[Idea\] "fully typed patterns" and function parameter type inference for those

**URL:** <https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175>\
**Category:** language design\
**Created:** [July 14, 2024, 8:36pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175 "2024-07-14T20:36:12Z")\
**Posts on this page:** 19\
**Page:** 1

<div class="post-metadata">

**Author:** ![JustusFluegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/justusfluegel/32/12338_2.png) [@JustusFluegel](https://internals.rust-lang.org/u/JustusFluegel)\
**Post date:** [July 14, 2024, 8:36pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/1 "2024-07-14T20:36:12Z")

</div>

I don't know if this is something that was discussed somewhere already but I haven't run across it yet so I am going to put it up to discussion here:

How about we have a notion of "fully typed patterns", i.e. patterns from which the type can be fully inferred, and drop the necessity for providing the type for parameters in functions that are such "fully typed patterns"

For an example (using a axum handler, where this pattern could be useful)

```rust
// before
fn handler(Json(data): Json<MyType>) -> ... { ... }
// with "fully typed patterns"
fn handler(Json::<MyType>(data)) -> ... { ... }

```

As you can see, the type here is fully given by the pattern already and as such the type annotation should be redundant.

This is explicitly not proposing to drop the requirement that function parameters need an explicit type in general - only in the special case where the pattern of the parameter itself can fully specify that type. That means there should be no huge complexity cost for the type resolution process from that, as well as being fully compatible with existing code, i.e. this shouldn't be breaking.

# Advantages

- Less repetition in parameters of functions taking patterns

# Potential disadvantages

I don't think there are any huge ones but maybe

- Slightly increased compile times (?)
- Slightly more complex error messages
- More complex to generate rustdoc maybe, since we need to figure out the concrete type for the param?

I would love to hear your thoughts!

( as an aside: the name "fully typed pattern" is choosen arbitrarily by me and there is probably a better way to call it )

---

<div class="post-metadata">

**Author:** ![FZs](https://avatars.discourse-cdn.com/v4/letter/f/85f322/32.png) [@FZs](https://internals.rust-lang.org/u/FZs)\
**Post date:** [July 14, 2024, 9:34pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/2 "2024-07-14T21:34:43Z")

</div>

One similar idea (or extension) to this I had recently is to allow a sort of type ascription inside patterns, which would (when used in a function signature) negate the need to annotate the argument type separately.

For example:

```
fn foo((string, vec): (&str, Vec<i32>))
// could be written as
fn foo((string: &str, vec: Vec<i32>))

```

I don't know what the blocker is on type ascription in general (it seems to have stalled since 2016, if I looked correctly?), but maybe it could be extended to include this?

---

<div class="post-metadata">

**Author:** ![JustusFluegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/justusfluegel/32/12338_2.png) [@JustusFluegel](https://internals.rust-lang.org/u/JustusFluegel)\
**Post date:** [July 14, 2024, 9:55pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/3 "2024-07-14T21:55:24Z")

</div>

Well I agree that type ascription in general seems like a overdue thing, but I would explicitly exclude it from this ( if this ever happens ) and keep it separate, to avoid making this more complex than it needs to be, at least for now.

I think type ascription was mostly stalled because of the additional complexity which the team at the time didn't feel like time well spent to solve, although with the note that it should be picked up again later - might remember wrong here tho.

( although I agree that the tuple case in particular is a very natural extension to this )

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 14, 2024, 11:08pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/4 "2024-07-14T23:08:59Z")

</div>

> [@JustusFluegel](#):
>
> ```rust
> // with "fully typed patterns"
> fn handler(Json<MyType>(data)) -> ... { ... }
> 
> ```

This was discussed back in 2018: [RFC: Generalized Type Ascription by Centril · Pull Request #2522 · rust-lang/rfcs · GitHub](https://github.com/rust-lang/rfcs/pull/2522#issuecomment-412322739)

I originally was in favour, but the discussion about the feature changed my mind. My position is now that having the `: $ty` always there is the right thing. Yes, `Wrapping(x: u32)` _is_ enough to deduce that the parameter is `Wrapping<u32>`, but I no longer think that we should be making people do that deduction. The type should be directly clear, both for humans and things like proc macros.

Thus I would prefer -- both here and in things like `static`s -- to instead make more convenient construction and pattern syntax, for use in places where the type is contextually clear. (Like how we have `Default::default()` already, how C++ has conversions from initializer lists, or C# added [target-typed `new` expressions](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-9.0/target-typed-new).)

So, for example, rather than having

```rust
fn demo(Point { x, y }: Point<f32>) // decl

demo(Point { x, y }) // cal

```

if we added, say, Swift-inspired

```rust
fn demo(.{ x, y }: Point<f32>) // decl

demo(.{ x, y }) // call

```

We can remove a bunch of the unnecessary repetition without losing the syntatically-clear type.

---

<div class="post-metadata">

**Author:** ![JustusFluegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/justusfluegel/32/12338_2.png) [@JustusFluegel](https://internals.rust-lang.org/u/JustusFluegel)\
**Post date:** [July 14, 2024, 11:14pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/5 "2024-07-14T23:14:50Z")

</div>

> I originally was in favour, but the discussion about the feature changed my mind. My position is now that having the `: $ty` always there is the right thing. Yes, `Wrapping(x: u32)` _is_ enough to deduce that the parameter is `Wrapping<u32>`, but I no longer think that we should be making people do that deduction. The type should be directly clear, both for humans and things like proc macros.

Maybe that was unclear but I explicitly _wasn't_ proposing to allow `Wrapping(x: u32)` - I agree that makes it substantially harder to read. I think `Wrapping::<u32>(x)` is reasonable though and already works today as a pattern.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 14, 2024, 11:22pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/6 "2024-07-14T23:22:15Z")

</div>

> [@JustusFluegel](#):
>
> I think `Wrapping::<u32>(x)` is reasonable though and already works today as a pattern.

That doesn't change how I think about it here. I still want the full type after the `:`.

To use your example, I'd rather

```rust
fn handler(.(data): Json<MyType>) -> ... { ... }

```

instead.

---

<div class="post-metadata">

**Author:** ![JustusFluegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/justusfluegel/32/12338_2.png) [@JustusFluegel](https://internals.rust-lang.org/u/JustusFluegel)\
**Post date:** [July 14, 2024, 11:26pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/7 "2024-07-14T23:26:22Z")

</div>

I don't know if I agree with you there (feel free to try to convince me tho if you want to 🙂 ) but if that syntax was supported I would probably prefer

```rust
fn handler(_(data): Json<MyType>) -> ... { ... }

```

over

```rust
fn handler(.(data): Json<MyType>) -> ... { ... }

```

since `_` already works as a "inferred" identifier in other places in rust today and `.` feels pretty unintuitive to me here, that might just be me tho.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 15, 2024, 12:20am UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/8 "2024-07-15T00:20:35Z")

</div>

> [@JustusFluegel](#):
>
> I would probably prefer
> 
> `fn handler(_(data): Json<MyType>) -> ... { ... }`

That's the big bikeshed for the feature, yup 😛

I agree that `_ { x, y }` makes some sense, but `_(data)` in particular it's less obvious, since that's not actually type position, and `_` is only inferred _type_ today, not "inferred identifier".

Per [https://rust-lang.github.io/rfcs/1506-adt-kinds.html#tuple-structs](https://rust-lang.github.io/rfcs/1506-adt-kinds.html#tuple-structs),

```rust
let x = Wrapping(4);

```

is a function call, so

```rust
let x: Wrapping<u32> = _(4);

```

would be an inferred function call, sorta? At that opens up all kinds of expectations that people could have that wouldn't actually make sense.

Thus I've been trying out the Swift-style `let x: Ordering = .Less;` style syntax in my examples (as opposed to `let x: Ordering = _::Less;` that's also often used) to see how it feels.

Probably not worth trying to solve that bikeshed in this thread, though. The important part of my post is the "infer in the pattern or expression, keep the type" direction, not the syntax for what that should look like.

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [July 17, 2024, 4:20am UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/9 "2024-07-17T04:20:31Z")

</div>

> [@scottmcm](#):
>
> ```rust
> fn demo(Point { x, y }: Point<f32>) // decl
> 
> demo(Point { x, y }) // cal
> 
> ```
> 
> if we added, say, Swift-inspired
> 
> ```rust
> fn demo(.{ x, y }: Point<f32>) // decl
> 
> demo(.{ x, y }) // call
> 
> ```
> 
> We can remove a bunch of the unnecessary repetition without losing the syntatically-clear type.

I like this a lot but I think there's one problem that it wouldn't solve, which is that sometimes you run into really complex types and it would be nice if you could localize the ascription to each variable individually. For example something that I'm working on involves parameter types like this:

```rust
.on_begin(|Fetch((mut pos, time, /*etc*/)): Fetch<(Each<CursorPos>, Res<Time>, /*Etc*/)>| {
    // ..
})

```

which would be much smoother to edit and read if each inner parameter could be labeled instead, I think:

```rust
.on_begin(|Fetch((
    mut pos: Each<CursorPos>,
    time: Res<Time>,
    // etc: Etc,
))| {
    // ..
})

```

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 17, 2024, 2:49pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/10 "2024-07-17T14:49:11Z")

</div>

> [@Yokin](#):
>
> `.on_begin(|Fetch((`

That's a closure, though, so has way more options and different inference possibilities.

I absolutely think we should allow things like

```rust
if let Ok(x: i32) = foo.parse() {

```

[https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/type.20ascription.20\*in.20patterns\*/near/213985025](https://rust-lang.zulipchat.com/#narrow/stream/213817-t-lang/topic/type.20ascription.20*in.20patterns*/near/213985025)

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [July 17, 2024, 5:28pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/11 "2024-07-17T17:28:29Z")

</div>

Having [some experience with the parsing side of type ascription](https://github.com/rust-lang/rust/pulls?q=is%3Apr+author%3Aestebank+is%3Aclosed+type+ascription)... Please, no. It's a huge headache for little gain.

I would only go along top-level pattern type ascription:

```rust
match foo {
    (a, b): (&str, Vec<i32>) => {}
    _ => {}
}

```

But that's only useful if `foo` is being inferred (or if we have anonymous enums).

```rust
if let Ok(x): Result<i32, _> = foo.parse() {

```

* * *

There are [other syntaxes](https://x.com/ManishEarth/status/1554869931195256833) that we can try instead that don't have the same issues as accepting infix `:` anywhere in a pattern:

```rust
foo.(as Type)
foo.as(Type)
foo.(: Type)
foo.<Type>

```

If you don't understand why I hate `:` ascryption everywhere so much, think what happens if you write `if let Ok(Foo:Bar(1), _) = foo {` when you meant `if let Ok(Foo::Bar(1), _) = foo {`. Even worse when it isn't a parse error `if let Ok(Foo:Bar, _) = foo {`.

---

<div class="post-metadata">

**Author:** ![scottmcm](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/scottmcm/32/2355_2.png) [@scottmcm](https://internals.rust-lang.org/u/scottmcm)\
**Post date:** [July 17, 2024, 5:42pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/12 "2024-07-17T17:42:26Z")

</div>

> [@ekuber](#):
>
> I would only go along top-level pattern type ascription:

I totally understand for arbitrary ascription.

What's your intuition if it's _only_ on bindings? Would that be as bad, or might it be tolerable?

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [July 17, 2024, 5:43pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/13 "2024-07-17T17:43:33Z")

</div>

You replied as I was editing my post. I think this answers your question directly:

> [@ekuber](#):
>
> think what happens if you write `if let Ok(Foo:Bar(1), _) = foo {` when you meant `if let Ok(Foo::Bar(1), _) = foo {`. Even worse when it isn't a parse error `if let Ok(Foo:Bar, _) = foo {`.

When `:` is only allowed at the top level, it becomes _much_ easier to do parse recovery in a sane way.

---

<div class="post-metadata">

**Author:** ![JustusFluegel](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/justusfluegel/32/12338_2.png) [@JustusFluegel](https://internals.rust-lang.org/u/JustusFluegel)\
**Post date:** [July 17, 2024, 5:51pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/14 "2024-07-17T17:51:26Z")

</div>

would these issues still exist if we choose another character or keyword, let's say, idk, `fits` or something ( or we might be able to repurpose `@` and just extend that syntax maybe? )

That would remove the ambiguity in

```rust
if let Ok((Foo:Bar(1),_)) = foo { ... }
// vs
if let Ok((Foo fits Bar,_)) = foo { ... }
// or
if let Ok((Foo @ Bar,_)) = foo { ... }

```

and would probably (idk, haven't done much with the compiler (yet), you are probably more qualified than me to judge something like that 🙂 ) enable way easier compiler errors / warnings.

---

<div class="post-metadata">

**Author:** ![Yokin](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/yokin/32/12030_2.png) [@Yokin](https://internals.rust-lang.org/u/Yokin)\
**Post date:** [July 17, 2024, 6:41pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/15 "2024-07-17T18:41:24Z")

</div>

I'm in favor of a different syntax cause you'd probably need it for named-field struct literals anyways.

I submit: `Ok(x: <i32>)`, where the ascribed type is wrapped in angle brackets. I think it would sidestep most path issues while still reusing existing Rust syntax. Downside is that it could still be malformed as a type with generics (`Ok(foo::<Bar>`), but I think that would always be a parse error in practice (no parameter list, and a lowercase type is unlikely).

But I like pretty much any syntax as long as I can insert & remove entries in a pattern without editing in 2 places.

---

<div class="post-metadata">

**Author:** ![mathstuf](https://avatars.discourse-cdn.com/v4/letter/m/958977/32.png) [@mathstuf](https://internals.rust-lang.org/u/mathstuf)\
**Post date:** [July 18, 2024, 11:25am UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/16 "2024-07-18T11:25:26Z")

</div>

> [@Yokin](#):
>
> Downside is that it could still be malformed as a type with generics (`Ok(foo::<Bar>`), but I think that would always be a parse error in practice (no parameter list, and a lowercase type is unlikely).

`inventory` uses generics that look like this: [inventory - Rust](https://docs.rs/inventory/0.3.15/inventory/#iterating-over-plugins)

---

<div class="post-metadata">

**Author:** ![ekuber](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/ekuber/32/1646_2.png) [@ekuber](https://internals.rust-lang.org/u/ekuber)\
**Post date:** [July 18, 2024, 6:00pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/17 "2024-07-18T18:00:32Z")

</div>

> [@Yokin](#):
>
> But I like pretty much any syntax as long as I can insert & remove entries in a pattern without editing in 2 places.

I am partial towards the `pat.as<Type>` syntax because it is the closest to existing syntax while also being far removed from allowed syntax that will make it easier to deal with. But there's something to be said about maintaining the symmetry with `let` bindings and `fn` arguments. I think that allowing `:` only in top-level patterns is a reasonable compromise. It is also the syntax that I've imagined if we were to ever have anonymous enums:

```rust
fn foo() -> Foo | Bar {
    if rand() > .5 {
        Foo
    } else {
        Bar
    }
}
fn main() {
    match foo() {
        foo: Foo => {}
        bar: Bar => {}
    }
}

```

If are to ever have that, then it would make sense for the same syntax to be used to aid inference and to select the implicit enum variant.

---

<div class="post-metadata">

**Author:** ![soqb](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/soqb/32/11300_2.png) [@soqb](https://internals.rust-lang.org/u/soqb)\
**Post date:** [July 31, 2024, 8:27pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/18 "2024-07-31T20:27:31Z")

</div>

ok. two points:

1. i think a good few of the (admittedly harrowing) issues @ekuber has solved have do with generalising type ascription to all patterns, which i don't think is what is this thread is/should be about:
  - this feature can be constrained just to places where colons are already accepted after patterns, so no match arms, no `matches!` macro, etc. the only places this syntax would be accepted (currently) is:

```rust
struct State<T>(pub T);

struct MyState;
let State(state: MyState);
fn foo(State(state: MyState), x: f32, y: f32);

```

1. if this syntax is (understandably) deemed too problematic wouldn't an even simpler version be less controversial?

```rust
// no generics, so just name is enough to fully infer:
struct InferByName {
    pub x: f32,
    pub y: f32,
}

fn do_something(InferByName { x: f32, y: f32 }, num: usize);

```

this could even allow more elaborate examples without extending syntax. all this would require is making function parameter types optional where simple inference can deduce the type by itself:

```rust
struct MyState {
    num: usize,
}

fn takes_state(State(state @ MyState { .. }), x: f32, y: f32);

```

---

<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:** [October 29, 2024, 8:27pm UTC](https://internals.rust-lang.org/t/idea-fully-typed-patterns-and-function-parameter-type-inference-for-those/21175/19 "2024-10-29T20:27:45Z")

</div>

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