-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Add generic associatedtypes and generalized supertype constraints #13012
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
docs/GenericsManifesto.md
Outdated
@@ -87,6 +87,21 @@ typealias StringDictionary<Value> = Dictionary<String, Value> | |||
var d1 = StringDictionary<Int>() | |||
var d2: Dictionary<String, Int> = d1 // okay: d1 and d2 have the same type, Dictionary<String, Int> | |||
``` | |||
### Generic associatedtypes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"associated types" here and below
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That’s how I would usually write it but I followed the precedent of “typealiases” that’s already in this document.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think that should be fixed too. In diagnostics we tend to say "type alias" not "typealias"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you suggest I include fixes for all of them in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@DougGregor any thoughts on this? Should I make the change from "associatedtypes" to "associated types" and "typealiases" to "type aliases" in this PR?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's probably worth a small note about how this might look from the perspective of somebody trying to conform to a protocol with generic associated types. The way I guess it would work is that a generic associated-type would require a generic type alias in the conforming type. So the generic type which fulfils that requirement may have more generic parameters, as long as they are all bound to parameters in the parent type or to concrete types.
So in your example, Wrapped<T>
could be a tuple of (Int, T)
, or an Array<T>
, or a Dictionary<SomeNestedGenericParameter, T>
. Is that correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@karwa This is a good idea. I'll be updating the PR with a note about this shortly. Your understanding is correct.
docs/GenericsManifesto.md
Outdated
@@ -592,6 +622,43 @@ one cannot directly specify `T`: either one calls `f` (and `T` is determined via | |||
```Swift | |||
let x = f<Int> // x has type (Int) -> Void | |||
``` | |||
### Conditional default arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Drive-by nit: please add an empty line above this (and also, above the heading "Generic associated types").
docs/GenericsManifesto.md
Outdated
@@ -592,6 +622,43 @@ one cannot directly specify `T`: either one calls `f` (and `T` is determined via | |||
```Swift | |||
let x = f<Int> // x has type (Int) -> Void | |||
``` | |||
### Conditional default arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Has this feature been discussed previously anywhere? I don't think we should add it to the document. The other two are "canonical" generics features that we have all talked about before.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not to my knowledge. It was on my mind while I was writing this so I added it. I can remove it if others agree that it shouldn’t be added.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'd rather have it removed from this PR and discuss it on swift-evolution a little bit first to get some basic syntax ideas in place. And I do want to discuss this... it's something that we might be able to use to help simplify associated type inference.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. I'll remove it when I update the PR and send a separate pitch on evolution.
I was thinking of this primarily as a way to reduce the pain of providing an interface like this but if it can help simplify associated type inference it would move up the priority list for me quite a bit. I have been seeing associated type inference issues in code that uses an overload set like this.
docs/GenericsManifesto.md
Outdated
} | ||
``` | ||
|
||
In the above example `Base` may be any non-final class or existential type. If `Base` is a class `Derived` must inherit from `Base`. If `Base` is an existential `Derived` may be any type that provides a compatible conformance, including a value type. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I had assumed that we were talking about a superclass constraint here, but I think it generalizes to existentials correctly. It's slightly bothersome to have the requirement on Base
be "non-final class or existential type", and I wonder if perhaps there's a looser definition that's okay. For example, maybe Base == Derived
is always okay, even if Base
is (say) a value type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's good feedback. I didn't word this precisely enough.
I think it makes sense to allow Base
to be any type. Derived
may be the same as Base
, a subclass of Base
when Base
is a non-final class or a conforming type when Base
is an existential. I definitely have use cases for existentials and I can imagine occasional problems if Base == Derived
was not allowed.
If it's not too difficult for an initial implementation, I would like to see this work with all subtype relationships including T: T?
and ((Base) -> Void): ((Derived) -> Void)
(as well as any other subtype relationships added in the future). This is really how I think of fully generalized supertype constraints.
Does that loosening make sense?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that makes sense to me.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be clearer to refer to these as "is" constraints? Derived may be any type so long as values of that type return true from a is Base
condition.
docs/GenericsManifesto.md
Outdated
@@ -592,6 +622,43 @@ one cannot directly specify `T`: either one calls `f` (and `T` is determined via | |||
```Swift | |||
let x = f<Int> // x has type (Int) -> Void | |||
``` | |||
### Conditional default arguments |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess I'd rather have it removed from this PR and discuss it on swift-evolution a little bit first to get some basic syntax ideas in place. And I do want to discuss this... it's something that we might be able to use to help simplify associated type inference.
163c6ab
to
08bf0b4
Compare
@DougGregor I have removed the discussion of conditional default arguments and updated the discussion of generalized supertype constraints. |
08bf0b4
to
2cff06d
Compare
This really should be merged 👍 |
@DougGregor Is this still a direction we want to go in? |
I personally would wish that at least generalized super type constraint would eventually become a thing in Swift. I bumped too many times where I couldn‘t tell the compiler some natural context related sub-type relation, which requires a runtime workaround instead of a compile-time type-safety. |
Got the green light from Doug ⛵️ @swift-ci please smoke test and merge |
This PR adds a few items to the generics manifesto. The first two were discussed briefly on Twitter where @DougGregor requested a PR to add them. I plan to followup with a pitch to Swift evolution for generalized supertype constraints after this is merged.