# Pre-RFC: Type parameter elision

**URL:** <https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400>\
**Category:** Uncategorized\
**Created:** [April 24, 2016, 5:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400 "2016-04-24T17:10:44Z")\
**Posts on this page:** 4\
**Page:** 1

<div class="post-metadata">

**Author:** ![kamalmarhubi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kamalmarhubi/32/1385_2.png) [@kamalmarhubi](https://internals.rust-lang.org/u/kamalmarhubi)\
**Post date:** [April 24, 2016, 5:10pm UTC](https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400/1 "2016-04-24T17:10:44Z")

</div>

I’m posting this to figure out of the idea has been proposed before, and if it’s worth expanding to a full RFC. I didn’t find anything similar on this forum or in the RFCs repo, but I could have missed something. It’s a bit rough with only headings for some Alternatives and Drawbacks, mostly to save on effort at this point. 🙂

- Feature Name: type\_parameter\_elision
- Start Date: (fill me in with today’s date, YYYY-MM-DD)
- RFC PR: (leave this empty)
- Rust Issue: (leave this empty)

# Summary

Allow eliding type parameters with trait bounds in function signatures where there are no relationships between the parameters.

# Motivation

Generic functions pay a big syntactic noise penalty compared to non-generic functions. Consider a function taking `&str`

```rust
fn foo(s: Vec<u8>)

```

We could make it more generally applicable by having it accept an `Into<Vec<u8>>` type, but that requires writing either

```rust
fn foo<S: Into<Vec<u8>>>(s: S)

```

or

```rust
fn foo<S>(s: S) where S: Into<Vec<u8>>

```

This RFC proposes allowing

```rust
fn foo(s: Into<Vec<u8>>)

```

This mirrors lifetime elision introduced in [RFC 141](https://github.com/rust-lang/rfcs/blob/master/text/0141-lifetime-elision.md).

In particular, this would make signatures for many functions accepting closures quite a bit nicer to read and write. For example, `slice::binary_search_by` could change from

```rust
binary_search_by<F>(&self, f: F) -> Result<usize, usize> where F: FnMut(&T) -> Ordering

```

to

```rust
binary_search_by(&self, f: FnMut(&T) -> Ordering) -> Result<usize, usize>

```

# Detailed design

Bare trait bounds would be accepted in function signatures anywhere a type parameter could appear.

- each such appearance introduces a type parameter bounded by the trait bound

- introduced type parameters appear after all explicitly provided type parameters

- bare trait bounds may only reference explicitly provided type parameters, or to type parameters in scope from outer `impl`s, `trait`s, or `fn`s.

## Examples

Here are a few examples from the standard library.

```rust
impl<T> Option<T> {
    pub fn unwrap_or_else(self, f: F: FnOnce() -> T) -> T { ... } // elided
    pub fn unwrap_or_else<F: FnOnce() -> T>(self, f: F) -> T { ... } // expanded

    pub fn map<U>(self, f: FnOnce(T) -> U) -> Option<U> { ... } // elided
    pub fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { ... } // expanded
}

impl CString {
    pub fn new(t: T: Into<Vec<u8>>) -> Result<CString, NulError> { ... } // elided
    pub fn new<T: Into<Vec<u8>>>(t: T) -> Result<CString, NulError> { ... } // expanded
}

pub trait FromIterator<A> {
    fn from_iter(iterator: IntoIterator<Item=A>) -> Self; // elided
    fn from_iter<T>(iterator: T) -> Self where T: IntoIterator<Item=A>; // expanded
}

impl <T> [T] {
    pub fn binary_search_by<T>(s: &[T], f: FnMut(&T) -> Ordering) -> Result<usize, usize> { ... } // elided
    pub fn binary_search_by<T, F>(s: &[T], f: F) -> Result<usize, usize> // expanded
      where F: FnMut(&T) -> Ordering { ... }
}

impl str {
    pub fn trim_left_matches<'a>(&'a self, pat: Pattern<'a>) -> &'a str { ... } // elided
    pub fn trim_left_matches<'a, P>(&'a self, pat: P) -> &'a str where P: Pattern<'a> { ... } // expanded
}

```

# Drawbacks

## Provides more than one way to write the same thing

## Introduces additional subtleties

# Alternatives

## Status quo

# Unresolved questions

## Precision in rules for elision and expansion

## Ability to elide type parameters for reference parameters

`AsRef` is a really useful place for this kind of elision, but it is used on references. As an example:

```rust
impl Path {
    pub fn new<S: AsRef<OsStr> + ?Sized>(s: &S) -> &Path { ... }
}

```

To elide the `S` parameter with the scheme in this RFC, we’d need to write

```rust
pub fn new<S: AsRef<OsStr> + ?Sized>(s: &AsRef<OsStr> + ?Sized) -> &Path { ... }

```

which is a trait object type.

## Grammar and parser support

I don’t know if it’s possible or easy to disabiguate

```rust
fn foo(s: SomeStruct<String>)

```

from

```rust
fn foo(s: SomeTrait<String>)

```

## Accepting traits in other positions

We could imagine allowing a trait bound to appear anywhere a type parameter can appear in signatures.

## Interaction / compatibility with the [`impl Trait` RFC](https://github.com/rust-lang/rfcs/pull/1522)

---

<div class="post-metadata">

**Author:** ![huon](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/huon/32/3698_2.png) [@huon](https://internals.rust-lang.org/u/huon)\
**Post date:** [April 25, 2016, 12:36am UTC](https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400/2 "2016-04-25T00:36:51Z")

</div>

You may be interested in [RFC issue #302](https://github.com/rust-lang/rfcs/issues/302) (and the original filing with more discussion: [#11196](https://github.com/rust-lang/rust/issues/11196)). I guess you may've already seen [the optional extension to the original `impl Trait` RFC covering this](https://github.com/aturon/rfcs/blob/62fe495d35f279a24eaef9b61dbe491145c2fb82/0000-abstract-return-types.md#function-arguments) too.

> [@kamalmarhubi](#):
>
> I don't know if it's possible or easy to disabiguate

It doesn't need to be distinguished at the grammar/parser level: they can result in the same internal AST structures, with the difference in behaviour guided by the compiler knowing what the thing actually is, i.e. if a name resolves to a trait it does the new thing, if it resolves to a struct it does the normal thing.

---

<div class="post-metadata">

**Author:** ![kamalmarhubi](https://sea2.discourse-cdn.com/flex002/user_avatar/internals.rust-lang.org/kamalmarhubi/32/1385_2.png) [@kamalmarhubi](https://internals.rust-lang.org/u/kamalmarhubi)\
**Post date:** [April 25, 2016, 1:19am UTC](https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400/3 "2016-04-25T01:19:34Z")

</div>

Thanks for those links. I had not seen the original `impl Trait` RFC at all, and had missed the RFC issue as I was looking for the keyword "elision".

> [@huon](#):
>
> the difference in behaviour guided by the compiler knowing what the thing actually is, i.e. if a name resolves to a trait it does the new thing, if it resolves to a struct it does the normal thing.

Ah yeah that makes sense.

---

<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:** [March 25, 2019, 8:26am UTC](https://internals.rust-lang.org/t/pre-rfc-type-parameter-elision/3400/4 "2019-03-25T08:26:06Z")

</div>

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