Rfcs: Proposal: Allow optional `type` keyword in generic

Created on 3 Jan 2018  Â·  6Comments  Â·  Source: rust-lang/rfcs

We have 3 kinds of generic parameters at present : type, lifetime and const value.

struct GenericType<T, 'a, const U> {}

Lifetime and const value starts with significant obvious punctuation and keyword, but normal type does not.

I'm proposing to allow type keyword in this situation.

// Multiply kinds of generic parameters involved
struct GenericType<type T, 'a, const U> {}

// only type parameter involved
struct GenericType<T1, T2> {}

Is there anybody agree with me that this may be clearer?

T-lang

Most helpful comment

The compiler didn't know the param C is a trait, so we can't use it as a bound.

That's because the param _is_ a type. This is absolutely intentional -- it's how Box<Trait> works, for example -- but the confusion it causes is why dyn is coming.

I do like the possibility of annotating all generic parameters with kinds, and hope that one day (no time soon, I know) code like foo<trait Tr, type Ty: Tr> becomes possible 🙂

All 6 comments

So to be clear:

struct Foo<T>(T);

and

struct Foo<type T>(T);

would be equivalent?

I guess it couldn't hurt to let users over-specify things if they like. But if this is done, I'm of the opinion that no linting should be done in favour of either approach. I prefer the less verbose version myself but understand those who want to be more explicit.

Yes, that was my intention. Just a non-breaking syntax change (new and old version are both allowed ), no more else.

I just realized that we can also use trait as type parameter as long as constrained by ?Sized. Example as below:

trait Fullness<C: ?Sized> {
    fn fullness(&self) -> f32;
}

trait Inventory {}
trait Tank {}

struct Foo;
impl Inventory for Foo {}
impl Tank for Foo {}

impl<T> Fullness<Inventory> for T where T: Inventory {
    fn fullness(&self) -> f32 { 0f32 }
}

impl<T> Fullness<Tank> for T where T: Tank {
    fn fullness(&self) -> f32 { 1f32 }
}

fn main() {
    let foo = Foo;
    Fullness::<Inventory>::fullness(&foo);
    Fullness::<Tank>::fullness(&foo);
}

But this seems like it works by accident. The compiler didn't know the param C is a trait, so we can't use it as a bound. ( dyn C is more accurate in this situation if dyn keyword is introduced). Maybe in future, we need a new kind of generic type which is a trait:

trait GenericTrait<trait T, ITEM>
{
   ...
}

If this happens, I think this version trait GenericTrait<trait T, type ITEM> looks better.

The compiler didn't know the param C is a trait, so we can't use it as a bound.

That's because the param _is_ a type. This is absolutely intentional -- it's how Box<Trait> works, for example -- but the confusion it causes is why dyn is coming.

I do like the possibility of annotating all generic parameters with kinds, and hope that one day (no time soon, I know) code like foo<trait Tr, type Ty: Tr> becomes possible 🙂

I really don't understand why the syntax has to be so non-uniform.
IMO it should by:

myValue: MyType // normal parameters

MyType: type // any type
MyType: MyTrait // any type implementing MyTrait
MyTrait: trait // any trait

type is the set of all types, a trait is a subset of all types (those implementing the trait). That means type Ty: Tr is redundant.

No, this would absolutely not make code any clearer.

Lifetime and const value starts with significant obvious punctuation and keyword, but normal type does not.

That's… kind of the point. The most frequently-used sort of generic parameter is a type. So, it should have the shortest syntax among the three – and, it in fact does. So that's right as-is. And since the other two kinds of generic parameters already have distinctive syntax, the reader already knows
that if a generic parameter doesn't, then it's a type. Consequently, there's no need to type type in order to type types as types by typing type before every type just so we know they are a type.

(Furthermore, there are linted naming conventions too, which help the reader distinguish between different kinds of entities, which again is the whole point in naming conventions. Type parameters should be short, usually 1 letter, starting with an uppercase letter, making them quite easy to recognize.)

Was this page helpful?
0 / 5 - 0 ratings