Skip to content
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

[SR-7818] Protocol can inherit from composition type with a superclass requirement #50354

Closed
AnthonyLatsis opened this issue May 31, 2018 · 17 comments
Assignees
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis

Comments

@AnthonyLatsis
Copy link
Collaborator

Previous ID SR-7818
Radar None
Original Reporter @AnthonyLatsis
Type Bug
Status Closed
Resolution Done
Environment

Xcode 9.3 (9E145)

Additional Detail from JIRA
Votes 0
Component/s Compiler
Labels Bug, TypeChecker
Assignee @slavapestov
Priority Medium

md5: d5877ab191d847e52d9c9ac98be1a4a8

Issue Description:

The following remains unnoticed by the compiler.

protocol Foo {}

class A {}

protocol Fooo: Foo & A {}

// Should show: Non-class type 'Fooo' cannot inherit from class 'A'

If I try conforming to Fooo:

class B: Fooo {} // 'Fooo' requires that 'B' inherit from 'A'

The compiler will stop complaining if I inherit from A.

@AnthonyLatsis
Copy link
Collaborator Author

// Protocols, generic parameters and associated types can inherit
// from subclass existentials, which are "exploded" into their
// corresponding requirements.

This is the comment next to the code responsible for allowing such behavior. Is this really correct?
cc @belkadan @DougGregor @slavapestov

@slavapestov
Copy link
Member

Both are supposed to work, but we haven't fully implemented the proposal yet.

@AnthonyLatsis
Copy link
Collaborator Author

Can you provide a link to the proposal? I really want to look at the motivation part.

@slavapestov
Copy link
Member

https://github.com/apple/swift-evolution/blob/master/proposals/0156-subclass-existentials.md

The motivation is you want to be able to define a protocol where all conforming types are required to be subclasses of another class.

@AnthonyLatsis
Copy link
Collaborator Author

What's wrong with the much more consistent protocol P where Self: Foo? It seems to work.
(I don't think we need this anymore with the introduction of where clauses on protocol declarations.)

WDYT?

@slavapestov
Copy link
Member

"protocol P where Self : Foo" has some bugs too. These are all related problems. I see no reason to support some variants of spelling this but not others; all of these should work:

typealias FooAndQ = Foo & Q
protocol P : Foo
protocol P : Foo & Q
protocol P : FooAndQ
protocol P where Self : Foo
protocol P where Self : Foo & Q
protocol P where Self : FooAndQ

@AnthonyLatsis
Copy link
Collaborator Author

I don't see a serious problem in having different ways to express things either, but the way with the composition is so inconsistent. It is literally making the protocol itself rather than Self inherit from a class, which is illegal in the language (except this case) and logically senseless.

@AnthonyLatsis
Copy link
Collaborator Author

@slavapestov If this isn't a bug then the SR is invalid. Have you assigned yourself to work on something or I can resolve it?

@slavapestov
Copy link
Member

This bug is useful because it's another case I need to fix (protocol inheriting from class-constrained composition).

I agree that there might be stylistic reasons to prefer one or the other, but converging all of these code paths to be handed in a more uniform manner will improve quality in various ways because its a good opportunity to refactor some messy code. I'm going to leave this bug open to track the work.

@AnthonyLatsis
Copy link
Collaborator Author

I'm sorry to bother, but I'm a bit confused: Is a protocol inheriting from class-constrained composition actually a bug or a feature? If it is a feature, where is the bug?

@slavapestov
Copy link
Member

I'm not sure I understand what you're trying to get at. I have various bugs assigned to me that describe various facets of the problem, namely that class-constrained protocols don't work. I'm not sure I have a specific bug for a protocol inheriting from a class-constrained composition not working, but once I fix the problems I will go through the various dupes I have and make sure all the user-provided test cases work.

@AnthonyLatsis
Copy link
Collaborator Author

Ok, I see. I was asking because I don't see a specific bug in my report.

One last thing: Is there a concrete proposal for the syntax of allowing protocols to inherit from a class-constrained composition (0156 introduces class-constrained compositions)? I want to bring up a proposal to eliminate that syntax in favor of Self: ... or at least discourage it if it's going to be source-breaking.

@slavapestov
Copy link
Member

I think banning the form you describe actually introduces a new special case where there was none, complicating the compiler.

In fact @DougGregor wanted to go the other direction and ban 'Self : ...' requirements from appearing in a protocol where clause.

My preference would be to allow both.

@AnthonyLatsis
Copy link
Collaborator Author

I think any of the options more or less complicates the compiler to a similar degree. Eliminating any of them would need additional logic to actually keep the feature for previous versions, since we care very much about compatibility. Keeping both requires accounting for overlapping uses. The only thing that I'm not happy about is the inheritance. Even if ': Foo & Class' is shorter than ': Foo where Self: Class', I am not convinced it is worth breaking fundamental rules, in particular, that a protocol can't inherit from a class. I know this is not what is happening under the hood, but those are quite different things, right? What is actually happening at the implementation level and how the language and it's rules are described, that is. This reminds me of raw types. But that syntax is convenient and doesn't really conflict with anything else.
Also, if we allow protocol P: Foo & Class, we should probably also allow protocol P: Class, Foo, which is even more inconsistent and strange. Time will pass and all of it might become ordinary, but I believe these kind of contradictions only bring more confusion to the language, something that Swift should avoid by being certain about the rules and consistent about how they are expressed in code.
These are the thoughts that motivate me to start a discussion on the forum. It would be interesting to hear Doug out as well.

@slavapestov
Copy link
Member

"protocol P : Foo, Class" was actually the original proposed syntax in SE-0156, but it wasn't implemented so we emit a diagnostic. "protocol P : Foo where Self : Class" was discovered on accident by users, and it doesn't really work completely. It was an oversight that it wasn't banned.

@slavapestov
Copy link
Member

On master, 'protocol Foo : SomeClass' now works, and 'protocol Foo where Self : SomeClass' generates an error.

@AnthonyLatsis
Copy link
Collaborator Author

I think we (and the current implementation) have settled by now that both : Class and where Self: Class should be accepted.

@swift-ci swift-ci transferred this issue from apple/swift-issues Apr 25, 2022
This issue was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug A deviation from expected or documented behavior. Also: expected but undesirable behavior. compiler The Swift compiler in itself type checker Area → compiler: Semantic analysis
Projects
None yet
Development

No branches or pull requests

2 participants