> On Mar 25, 2017, at 3:46 PM, Brent Royal-Gordon <[email protected]>
> wrote:
>
>> On Mar 24, 2017, at 10:09 AM, Douglas Gregor <[email protected]> wrote:
>>
>>> I'm actually not worried about methods so much as properties. KVC is
>>> completely untyped on the Objective-C side, and there are several different
>>> mechanisms there which use KVC with poorly validated external strings, like
>>> bindings, sort descriptors, and predicates. Tons of migration errors are
>>> going to escape into production if we do this,
>>
>> We can avoid these by migrating conservatively (have the migrator add @objc
>> everywhere it’s inferred in Swift 3).
>
> We can do that, but personally, I really hate these kinds of conservative
> migrations. It might be unavoidable, though.
>
>>> Have you considered a deprecation cycle (for instance, having Swift 4
>>> thunks log a warning that they're going away in Swift 5)?
>>
>> I think Swift 3 -> Swift 4 is the deprecation cycle, no?
>
> But there was no indication during Swift 3 that this feature was going away.
> As I understand it, a deprecation cycle introduces advanced warning of a
> change so you have time to prepare for it; that's not available here.
The deprecation cycle is however long Swift 3 compatibility mode is around:
Swift 3 compatibility mode can start warning about uses of the deprecated @objc
inference—both in the compiler proper and at runtime via logging.
>
> My concern is that, because the tools are not really aware of KVC, we can't
> count on the compiler to lead developers to missing `@objc` properties. Folks
> are only going to find those mistakes through testing, and they're inevitably
> going to miss a few spots. So some poor schmuck is going to migrate their
> code to Swift 4 without realizing this is an issue at all, accidentally miss
> a few spots in their testing, ship it, and have to deal with weird crashes
> out of nowhere. They're going to say, "My code worked just fine before. Swift
> 4 broke it!" And they won't be wrong.
>
> I'd be more comfortable with a version-long deprecation cycle that gave
> developers plenty of time to notice these bugs. Failing that, I'd at least
> like to see them get backtraces containing a symbol name like
> `YouCantInvokeASwiftMemberThroughTheObjectiveCRuntimeUnlessItsMarkedWithAtObjc`
> so the nature of the problem and its solution will be more obvious.
> (Preferably, this function would log the instance and selector, so if people
> got both the logs and the backtrace, the diagnosis would be as simple as we
> can make it.)
We can do logs with a backtrace. This is fantastic suggestion also made earlier.
> (Actually, I wonder if we could install a `-doesNotRecognizeSelector:`
> override in Swift classes which looked for a matching member in the Swift
> runtime metadata and, if it found one, called the `YouCantInvoke…` function?
> That would be lower overhead than generating stubs at compile time, and the
> slowness of searching the runtime metadata wouldn't matter much since it was
> going to crash anyway. I'm not sure if it might remove useful information
> from the backtrace, though. Maybe in Swift 5, when these bugs will be more
> rare. Or maybe in `SwiftObject`.)
The Objective-C thunks are nontrivial code patterns that we won’t be able to
generate at runtime without a ton of infrastructure, so we’re stuck with
statically generating the stubs. Also, we don’t have Swift runtime metadata for
methods now.
>
>> Plus, inheritance from an Objective-C class is often incidental: you do it
>> because you need an NSObjectProtocol conformance, or something else expects
>> NSObject. I haven’t heard of developers inheriting from NSObject solely to
>> get @objc inference for their members.
>
> You do it because you need a particular object to interact with Objective-C.
> In that circumstance, I don't think the compiler is wrong to assume that you
> want to expose as many members as possible to Objective-C.
You don’t need it for a particular object to interact with Objective-C; you
need it so that the class itself is visible to Objective-C source code. Or
because something forced you to inherit from NSObject (e.g,, the
NSObjectProtocol, which I mentioned in my reply to Charles).
>
>>> you already have to specify `dynamic` to avoid optimizations;
>>
>> Conceptually, ‘dynamic’ is orthogonal to ‘@objc’. In today’s implementation,
>> we can only implement ‘dynamic’ via the Objective-C runtime, hence this
>> proposal’s requirement to write both.
>
> I understand that, but again, I think it's defensible for the compiler to
> assume that, if you want dynamic behavior in a class where you've already
> enabled Objective-C interop, you probably want that dynamic behavior to be
> compatible with Objective-C.
>
> I guess we just take different standpoints on Objective-C interop. My belief
> is that, if you state an intention to have a type interoperate with
> Objective-C, Swift should try to expose as many of its members to Objective-C
> as possible. I think you believe that Swift should expose as *little* as
> possible to Objective-C.
I think that exposing as many of its members to Objective-C as possible is both
hard to reason about (something your idea below would address) and has an
unacceptable impact on code size.
> Because of that difference, I actually think I'd be *more* likely to support
> removing inference by requiring an explicit `@nonobjc` on members of
> Objective-C-compatible classes which aren't compatible with Objective-C. That
> is, writing:
>
> class Foo: NSObject {
> var bar: Int?
> }
>
> Is an error; you have to write:
>
> class Foo: NSObject {
> @nonobjc var bar: Int?
> }
>
> I don't really like that answer very much, but I like it more than I would
> like requiring `@objc` if `bar` were a plain `Int`.
Interesting. I floated the idea of doing this for members of @objc protocol
extensions
extension UITableViewController {
func objCWontSeeMee() { } // error: must have explicit @nonobjc to
acknowledge that this will not be available in @objc.
}
but almost nobody liked that idea due to the boilerplate it caused. I think
they’ll yelp louder if they have to do it in all of their NSObject-derived
classes.
- Doug
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution