Pre-RFC Permit limited shadowing of type parameters in associated functions


#1

I would like to propose the following change.

Summary

Permit type parameters for associated functions that does not receive self (et. al.) to shadow type parameters specified in the impl to permit less verbose expressions when constructing instances of a generic type.

Example

Consider the following:

pub struct Foo<T, U>(Option<T>, Option<U>);

pub fn existing<T>() -> Foo<T, u32> {
    Foo(None, None)
}

impl<T> Foo<T, u32> {
    pub fn existing() -> Foo<T, u32> {
        Foo(None, None)
    }

    // Would be supported through this proposal:
    pub fn proposed<T>() -> Foo<T, u32> {
        Foo(None, None)
    }
}

fn main() {
    let foo = existing::<u32>();
    let foo = Foo::<u32, _>::existing();
    // Would be supported through this proposal:
    let foo = Foo::proposed::<u32>();
}

Motivation

This proposal permits writing constructors where you only need to specify relevant type parameters. The rest can be inferred.

(Thanks to @durka!) This appears to already be supported in the language through the following approach:

pub trait Same<T> {}
impl<T> Same<T> for T {}

impl<T> Foo<T, u32> {
    pub fn proposed<U: Same<T>>() -> Foo<T, u32> {
        Foo(None, None)
    }
}

While the existing support could act as an argument against this proposal, I’d argue that it is a bit too esoteric. The fact that it works appears to be a proof of concept that it can be implemented by treating variable shadowing as syntactic sugar for the above.

Thanks!


#2

The second “existing” example does not compile. It should be corrected to:

let foo = Foo::<u32, _>::existing();

#3

@kornel Fixed. Thanks!


#4

Which is why we need partial turbofish as opposed to the turboswords of today =)


#5

@Centril Yeah, I think partial turbofish will help. It was mentioned in previous discussions.

Are the two proposals mutually exclusive?

What I’m thinking about this proposal compared to PT is:

  • It’s a different thing that has one overlapping use-case (associated functions).
  • It’s smaller in scope (?).
  • This potentially covers a soundness gap - making free and similar associated functions differ less for the user.

#6

It was only a comment on @konel’s nit - you should be able to write Foo::<u32>::existing() in the future. Other than that they are entirely orthogonal (I think) and has no bearing on whether we should do what you propose here or not.


#7

I see. Thanks for the clarification!