Skip to content

[Docs] Rework educational note on protocol type non-conformance #33735

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 3 commits into from
Sep 1, 2020

Conversation

xwu
Copy link
Collaborator

@xwu xwu commented Sep 1, 2020

The current educational note on protocol type non-conformance has been insufficient to explain the situation to a user encountering the diagnostic in question.

This is an attempt to rework the text to incorporate more of the necessary discussion; it includes an example with intuitive protocol semantics which illustrates why existential types cannot conform to their own protocols in the general case, and it gives a brief explanation why it is not permitted currently in situations where it might be possible to relax the restriction.

Moreover, since The Swift Programming Language and Apple documentation now pervasively use the term, this reworking elevates the term "existential type" and uses it more consistently throughout the text to contrast the type from the protocol with which it is associated.

@xwu xwu requested a review from owenv September 1, 2020 02:36

In Swift, a protocol that does not have `Self` or associated type requirements can be used as a type. You can use a variable or constant of a protocol type, also called an __existential type__, to hold a value of any conforming type:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it should be “contravariant Self”, because this works:

protocol P {
  func foo() -> Self
}

struct S: P { 
  func foo() -> S {
    self
  }
}

let p: P = S() // okay

Copy link
Collaborator Author

@xwu xwu Sep 1, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The details are more applicable to the other educational note on PATs. However, I'm a bit surprised that this works, since var foo: Self { get } does not.

Edit: I've opened a draft update of the other docs, where I think the details are most salient for what you point out. Still not sure why the discrepancy between func and var here though...

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I'm thinking on the right track, just a thought to throw about:

One of the differences between functions and computed variables is that only functions can throw errors. Error is the only protocol in Swift that has self-conformance. Is there any special handling added to functions because of Error, that might explain the discrepancy?

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 not just Error. Any and many Obj-C protocols are also self-conformant.

Copy link
Contributor

@owenv owenv left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this looks like a nice improvement! Now I just need to figure out hosting for these so we have something nicer to link to from forum posts 😄

@xwu
Copy link
Collaborator Author

xwu commented Sep 1, 2020

@swift-ci smoke test and merge

@swift-ci swift-ci merged commit 75b1a7e into swiftlang:master Sep 1, 2020
@xwu xwu deleted the existential-edu branch September 1, 2020 12:48

The Swift protocol `Error` has no required members and, when used as a type, conforms to itself; `@objc` protocols with no static requirements can also be used as types that conform to themselves.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any is also self-conforming, though it's not technically a protocol.

Two other notes about self-conforming protocols that may be relevant:

  1. By definition, self-conforming existential types satisfy the condition P.self is P.Type. (Although Swift's current casting implementation has bugs around this.)

  2. Self-conformance is necessary for certain generic constructs in Swift to work. You gave a basic example for generic functions, but it also applies to generic types. It's worth talking about workarounds in this document, as this seems to be the primary reason that people run into this diagnostic: They're trying to do perfectly reasonably things with generics that Swift in its current form does not support.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@tbkka Thanks!

Regarding (1), are the bugs sufficiently rare that we can tell users that this relationship is true of today's Swift?

Regarding (2), can you help outline what you're referring to in terms of its applicability to generic types? Besides manual type erasure, what other workarounds are you thinking of in that case?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

  1. Unfortunately, Swift 5.3 only handles this correctly for Any

  2. Besides manual type erasure, you can avoid self-conformance problems by just using protocol-typed arguments and ivars directly, instead of making them generic:

// This has problems with protocol-typed arguments:
func f<T:P>(t:T) { ... }
// Instead, just use the protocol-typed argument directly:
func f(t: P) { ... }

// Similarly for generic types.
// Instead of:
struct Foo<T:P> {
    let t: T
    ....
}
// Just use a protocol-typed ivar directly and avoid the generic
struct Foo {
   let t: P
   ...
}

Because of how Swift handles protocols and generics, the latter is essentially the same but avoids the self-conformance problem.

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.

6 participants