Open AliSoftware opened 5 years ago
I think this is correct behavior. A non-NSObject-inheriting class can have @objc
members (which means "exposed to the ObjC runtime", not "included in the generated header"); it's just not often that useful to do it. @DougGregor?
Ha!
If it is, I'm curious of a use case though… how could the members be exposed to the ObjC runtime if the class isn't? How would the ObjC runtime access and use them then? It's not like if we could class_copyPropertyList
to get them if the class itself isn't exposed, right?
You'd have to pass an instance of the class to Objective-C yourself, but you can certainly do that if you want. (Also, strictly speaking these classes can still be found through NSClassFromString.)
The original motivation for accepting this was to allow pure Swift classes to conform to Objective-C protocols. Given how many Objective-C protocols depend on NSObject-ness in practice, though, I'm not sure how useful it's actually turned out to be.
Swift classes not inheriting NSObject are still valid Objective-C classes, and can have `@objc` methods... they just won't be visible to Objective-C source code because they don't show up in the generated header. In that sense, it's not wrong to allow `@objcMembers` on a Swift class not inheriting from NSObject.
My inclination is to say this is not a bug, and say that we don't want a warning for this case: it's not wrong to have `@objcMembers` without inheriting NSObject, and if we add a warning it would suggest that `@objc` and `@objcMembers` are strongly tied together—but they really aren't in the model. Adding a warning also requires adding a way to suppress that warning (e.g., by adding`@nonobjc`).
@AliSoftware, do you still feel that a warning would be beneficial here?
@DougGregor But to be honest, even if @objc
and @objcMembers
are initially to give exposition to the ObjC runtime more than to add to the generated header, given that 90% of their use cases are to make a Swift class be exposed to the ObjC source code more than just the runtime, I feel like a warning would be beneficial.
But you're also right that if we add a warning (which would be equally triggered by @objcMembers
on a non-NSObject class but also on an @objc
annotation on a property or method of a class that is itself not exposed to ObjC), we might need a way to disable it as it would apparently be a correct construction for the very rare and unlikely cases that it would be intentional
Maybe a better/ideal solution to the problem would be to add a way (accessible from the IDE like under the 4-squares Ctrl-1 menu (View > Standard Editor > Show Related Item) or something?) to help diagnose why a class isn't exposed to ObjC source code (why it won't appear in the generated header)?
That way I'd have been able to select my class, use that "Ctrl-1 > Generated Interface > Diagnose" hypothetical menu, and it would tell me "this class isn't exposed to ObjC source code because it's not inheriting NSObject" or something?
And would work similarly when selecting a property or function of a class
maybe also emitting an explaination that a function in an {{ @objc enum Foo: Int }} can't be exposed as ObjC don't support functions in enums, and other similar diagnostics?
I realize that might this idea will probably be more work than just adding a warning though, and I might be asking for that just because I lost a lot of time recently because of that, which a diagnostic could have prevented, so was quite frustrating… but it's not the first time I saw situations like that so some help from the compiler to diagnose that (on demand or via a warning) would definitively have helped those times ;-)
@objc
really isn't about the header. There are all sorts of circumstances where it won't show up there:
The containing class is generic, or has generic ancestry.
The method is private
.
The containing class is nested (this one's actually inconsistent, which is a bug).
We're not going to have warnings in all those cases.
Yeah, that's why I said that a better ideal solution would be something different and separate from just something specifically tied to @objc
in the end as it's not that related to the generated header after all, like some on-demand diagnostics using Ctrl-1 > Generated Interface > Analyze" or something to tell us why a class doesn't appear in the generated header, as I admit this was the main reason why I lost a lot of time in the first place, more than the issue related to this.
Maybe you'd prefer we close that bug report related to @objc
and @objcMembers
, marking it as behaving as expected and not a bug, and I open a different one related to the debugging of why a class wouldn't appear in the generated header (so one to suggest we have a way to diagnose those cases like the ones you mention above to help better understand what reasons would explain a class not to be in the generated header for those cases we intend to make it visible to the ObjC source code but don't understand why it isn't)
Additional Detail from JIRA
| | | |------------------|-----------------| |Votes | 0 | |Component/s | Compiler | |Labels | Bug | |Assignee | None | |Priority | Medium | md5: 924803a6681795b962e04f6332511076Issue Description:
Summary
A pure Swift class non-inheriting NSObject can be marked as
@objcMembers
Expected results
The compiler should error when classes not inheriting NSObjects are declared as
@objcMembers
, the same way it errors about those with@objc
Actual results
No error (and the class is omitted from the generated interface)
Example
When annotating with
@objc
we get the following expected error:But when annotating with
@objcMembers
we don't and this compiles without any error: