Rust: Namespaced enums are weird in regard to generic paramters

Created on 18 Feb 2015  路  11Comments  路  Source: rust-lang/rust

Enum variants are namespaced now, but applying generic paramters to them in expressions still works as before, which means the correct way to type annotate a Option in a expression is to do this:

enum Option<T> {
    Some(T),
    None
}
let x = Option::Some::<u32>(1);

However, this is inconsistent with other namespaced constructs, like this:

struct Foo<T>(T);
impl<T> Foo<T> { fn new(t:T) -> Foo<T> { Foo(t) } }

let x = Foo::<u32>::new(1);

// With UFCS
let f = Option::<u32>::and as fn(Option<u32>, Option<u32>) -> Option<u32>;

Generally, type parameters of an item are supposed to go on that item in a path, but for enum variants this is not the case.

As a backward compatible solution to this, enum variants could be made to work similar to associated items of traits:

Option::Some      // Generic item fn<T>(T) -> Option<T>
Option::<T>::Some // Concrete instantiated item fn(T) -> Option<T>
I-needs-decision

Most helpful comment

I just spent some time running into this issue. I agree it was the right decision not to block 1.0 on it, but does that mean the issue will never be addressed?

I think the turbofish syntax should also be supported for orthogonality, since it is not at all clear to new Rustaceans such as myself that an enum should be thought of differently.

All 11 comments

nominating for discussion at triage meeting. Sounds like there might be a 1.0 issue to address here.

@alexcrichton points out that it is _nice_ to write None::<T>

But it does seem like an inconsistency, i.e. a wart.

P-backcompat-lang, 1.0 beta, I-needs-decision.

Yeah, the ability to have None::<T> doesn't really need to go, but Option::<T>::None should also work for consistency... Tricky decision.

This is not clearly an inconsistency. It depends on how you view enums. In particular, at least under some of the "virtual struct" proposals, enums were kind of "shorthand" for something like:

abstract enum Option<T>;
enum Some<T> : Option<T>;
enum None<T> : Option<T>;

in which case the current behavior seems perfectly consistent.

We are going to keep our current syntax/semantics, largely because we like being able to write e.g. None::<T>, and we are not convinced supporting a second way via Option::<T>::None is worth blocking 1.0 or 1.0 beta, and if there is a good argument for supporting it, we can add it backwards compatibly via the RFC process.

I just spent some time running into this issue. I agree it was the right decision not to block 1.0 on it, but does that mean the issue will never be addressed?

I think the turbofish syntax should also be supported for orthogonality, since it is not at all clear to new Rustaceans such as myself that an enum should be thought of differently.

I would be open to an RFC proposing a solution, but I don't think it's a priority for us on the lang-team -- happy to discuss it a bit though if you'd like to drive it! Maybe open a thread on internals?

@nikomatsakis I would love to land a feature (even a tiny one)!

Question: does it not being a priority for the lang team (understandable, given all the work going on) mean that even if we hash out a solution and I am able to implement it (neither being a given, you understand ;)) that it would still be unlikely to make it into the codebase?

Or does it simply mean the team has limited available cycles for hashing out the feature and implementing it themselves?

Thank you for the invitation, @nikomatsakis. 馃憤

@U-007D

Or does it simply mean the team has limited available cycles for hashing out the feature and implementing it themselves?

This is what I meant, in this case.

I'd also be very interested in additionally allowing the normal turbofish syntax for variants of generic enums (e.g. Option::<T>::None).
I've been using Rust a lot for the past years and was always wondering why the normal turbofish doesn't work for enums (because you'd expect it to)..

And it's very inconsistent/weird having to write MyGenericEnum::MyVariant::<i32, usize>(x)
(when the types can't be inferred from the args passed to this variant constructor).

I want to be able to write MyGenericEnum::<i32, usize>::MyVariant(x) instead.

I'd be willing to write a RFC for this. I haven't written a RFC before, but read a lot of RFCs, this one seems to be a good "first RFC" to write, right?


Btw, I also wish accessing variants would work for aliased (monomorphized) enums, e.g.:

type Foo = MyGenericEnum<i32, usize>;

...

let x = Foo::MyVariant(y);

And also for aliased (still generic) enums, e.g.:

type Foo = MyGenericEnum;

...

let x = Foo::<i32, usize>::MyVariant(y);

@Boscop agreed--it would be nice for this to be consistent. I'm wrapping up another small Rust feature and have started a new job, so this is all yours, if you want it. Thanks for taking this on!

Was this page helpful?
0 / 5 - 0 ratings