Skip to content

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

Merged
merged 1 commit into from
Nov 19, 2019

Conversation

anandabits
Copy link
Contributor

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.

@@ -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
Copy link
Contributor

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

Copy link
Contributor Author

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.

Copy link
Contributor

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"

Copy link
Contributor Author

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?

Copy link
Contributor Author

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?

Copy link
Contributor

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?

Copy link
Contributor Author

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.

@@ -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
Copy link
Collaborator

@xwu xwu Nov 18, 2017

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").

@@ -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
Copy link
Contributor

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.

Copy link
Contributor Author

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.

Copy link
Member

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.

Copy link
Contributor Author

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.

}
```

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.
Copy link
Member

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.

Copy link
Contributor Author

@anandabits anandabits Nov 20, 2017

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?

Copy link
Member

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.

Copy link
Contributor

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.

@@ -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
Copy link
Member

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.

@anandabits
Copy link
Contributor Author

@DougGregor I have removed the discussion of conditional default arguments and updated the discussion of generalized supertype constraints.

@anandabits anandabits changed the title Add generic associatedtypes, generalized supertype constraints and conditional default arguments Add generic associatedtypes and generalized supertype constraints Nov 24, 2017
@DevAndArtist
Copy link
Contributor

This really should be merged 👍

@CodaFi
Copy link
Contributor

CodaFi commented Nov 17, 2019

@DougGregor Is this still a direction we want to go in?

@DevAndArtist
Copy link
Contributor

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.

@CodaFi
Copy link
Contributor

CodaFi commented Nov 18, 2019

Got the green light from Doug

⛵️

@swift-ci please smoke test and merge

@swift-ci swift-ci merged commit f507e7b into swiftlang:master Nov 19, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

8 participants