Repository navigation
Tracking issue for Self and associated types in struct expressions and patterns #37544
Description
Activity
This doesn't feel complete to me without also allowing
Selffor tuple and unit-like struct, and enum expressions. It just feels very inconsistent being able to dofn new() -> Self { Self { ... } }, but notfn new() -> Self { Self(...) },fn new() -> Self { Self }, andfn new() -> Self { Self::Variant }.I was looking forward to this feature, so I don't have to repeat type names in as many places, but in its current state this is too inconsistent to be widely applicable.
Reacted by Zack M. Davis, Tim and Kim SimmonsSelf::Variant(andAlias::Variantin general) is in the queue (#26264), it's just not implemented yet.Self(..)forstruct S();orSelfforstruct S;would be some kind of new language entity, value alias (different from just a constant) referring to the original value - struct constructor. It's certainly can be hacked into the compiler, but I'd like to have some more foundation under it and see wider picture - how else these value aliases can be used, how they are related to possible pattern aliases, etc.Self::Variant (and Alias::Variant in general) is in the queue (#26264), it's just not implemented yet.
👍
Self(..) for struct S(); or Self for struct S; would be some kind of new language entity, value alias...
I don't want to get off-topic here, but I find it odd that a type alias does not give you the full capabilities that you can do when using the original type name.
When one says
struct Foo, does that not only create a new type, but also some kind of special entity that allows value construction that is different than a type, and these two things are under the same name? Is there a fundamental reason why a type itself cannot be used for these purposes? If this is too complicated to answer here, that's okay. I don't want to hijack this thread too much.Reacted by ShikChenIs there a fundamental reason why a type itself cannot be used for these purposes?
It's possible, just messy.
Suppose, for example, that we have an expressionA::B(0, 1)It may a function call, or it may be a tuple struct construction.
We need to resolveA::Bto understand what is it.
Rust have two primary namespaces - one is for types, and the other is for values. This is pretty fundamental thing that can't be changed backward compatibly.
Functions are defined in value namespace and types like structs are defined in type namespace.If the "type itself" is used for looking up tuple struct constructors, then we need:
-
Search
A::Bin both namespaces, this kind of contradicts to the point of namespaces. -
Set up namespace priorities. What if both function
A::Band structA::Bexist? Should we prefer one of them or report an error? -
Ok, suppose we prefer a function. Now we need to resolve
A::Bin value namespace and if this resolution fails, then we need to resolve it again in type namespace.
Name resolution happens in two phases:- Primary resolution pass, based only on names, used for everything except for associated items.
- Resolution in type checking, used for associated items (method resolution, etc.), this jumps through various type checking hoops (trait selection, inherent impls, parameter substitution, autoderef for methods) to find the correct resolution.
If
A::Bis not resolved in value namespace during the first pass, then we can't simply search type namespace, becauseA::Bmay be, for example, a method. We need to record partial resolutions in both namespaces and proceed to type checking when full resolution is completed and we select a function if it's found and a type otherwise.
Instead of doing all this, tuple/unit structs define additional function/constant-like items in value namespace which then used during resolution of
A::B(0, 1), but can also be used in other ways like normal functions/constants. So, namespaces stay clearly separated and there's no need to disambiguate between types and values and keep both resolutions until type checking. But it's still possible to implement this fall back to types backward compatibly, even now.Reacted by crumblingstatue-
- addedB-RFC-approvedBlocker: Approved by a merged RFC but not yet implemented.Blocker: Approved by a merged RFC but not yet implemented.B-unstableBlocker: Implemented in the nightly compiler and unstable.Blocker: Implemented in the nightly compiler and unstable.T-langRelevant to the language teamRelevant to the language team
on Nov 14, 2016 4 remaining items
My main concern is that perhaps it is confusing to allow types (and not just structs) at all!
This is my concern too, however, my understanding is that this ship sailed some time ago and we allow all sorts of things in the ident position of a struct literal.
This is my concern too, however, my understanding is that this ship sailed some time ago and we allow all sorts of things in the ident position of a struct literal.
Off hand I'm not sure what you mean... have an example? Do we allow e.g. type aliases?
@nikomatsakis We do allow type aliases and this is what I had in mind. FWIW, we also allow, e.g.,
Foo::<u32> { ... }. However, associated types in that position do not work.So in particular this does work:
struct Foo<T> { x: T } type Bar = Foo<u32>; fn main() { let x = Bar { x: 22 }; }
@rfcbot reviewed
ping @nikomatsakis
I hoped to get this into the upcoming beta :(@petrochenkov We can backport the stabilization. Looks like this was blocked on @pnkfelix who's been on vacation. I'll try to get a hold of him now.
@rfcbot reviewed
🔔 This is now entering its final comment period, as per the review above. 🔔
psst @nikomatsakis, I wasn't able to add the
final-comment-periodlabel, please do so.- addedfinal-comment-periodIn the final comment period and will be merged soon unless new substantive objections are raised.In the final comment period and will be merged soon unless new substantive objections are raised.
on Dec 21, 2016 The final comment period is now complete.
@petrochenkov you want to prepare stabilization PR?
@petrochenkov you want to prepare stabilization PR?
- added a commit that references this issue
on Jan 27, 2017
I'm going to add a feature gate according to #37035 (comment), this is a corresponding tracking issue.