[Idea] Further directions for id-as-Any


(Brent Royal-Gordon) #1

In the current Swift 3 betas, value types can now be passed into Objective-C as opaque box objects. A couple of reviews are currently running which tweak this bridging, exposing Optionals and NSValue/NSNumber-compatible types in more natural ways. These are all Good Things. I'd like to look ahead and sketch out a way this feature could evolve further. This will not be detailed, and much or all of it may be out of scope for Phase 1.

Firstly, I think we could make boxed value types much more usable from Objective-C:

1. We could bridge selector calls to equivalent Swift methods, where those methods are Objective-C-compatible (other than being on a value type). This could actually be done dynamically if enough metadata is available.

2. We could generate a separate subclass of our box class for each bridged Swift type. This could actually *still* be done dynamically, I believe.

3. We could permit value types to conform to @objc protocols. This would open up several nice features to us; perhaps most importantly, a value type could conform to NSCoding and thereby participate in Foundation's serialization mechanisms. I suspect that at this point, the box subclasses would have to become "real", i.e., registered at load time. (Perhaps they're only greedily registered if they have an explicit @objc?)

4. We could explicitly declare the bridged methods, properties, and conformances in the generated -Swift.h file, thereby making Swift value types directly available to Objective-C, where they can be allocated, accessed, and manipulated in boxed form.

Secondly—and separately, but relatedly—I believe a few simple changes could liberalize the @objc-compatibility rules, permitting many more members to be exposed to Objective-C:

1. We could run "omit needless words" in reverse when exposing Swift methods to Objective-C. This would prevent overloads from clashing in Objective-C, and would also have the bonus feature of producing more idiomatic Objective-C interfaces. (Incidentally, is a change considered source-breaking if it breaks Objective-C code, not Swift code?)

2. We could grant access to members using Swift-only type features by allowing the Objective-C versions to have looser types than the Swift versions, and dynamically enforcing the missing constraints instead. For instance, a member with a complicated `where` clause might omit the clause in its Objective-C declaration, but enforce it with a dynamic test.

3. I suspect it might be possible to expose generic types to Objective-C with some custom class methods. For instance, a Swift type with `Key` and `Value` type parameters might have `+classWithKey:(Class)keyClass value:(Class)valueClass` and +`allocWithKey:(Class)keyClass value:(Class)valueClass` methods on it.

Are these potential features of interest? If so, to what extent do they affect binary compatibility? On the one hand, they are extensions, adding transparency to things which are currently opaque. But on the other hand, they will presumably involve generating type metadata.

···

--
Brent Royal-Gordon
Architechies


(Will Field-Thompson) #2

This might be useful for some cases, but I have some concerns about tying
serialization to this. I would rather see a Swift-centric rethinking of
serialization than having the runtime dynamically register Objective-C
classes anytime I want to serialize something. Plus, that seems like it's
leaving Linux users out in the cold for serialization — although I'm
primarily a macOS/iOS user, so maybe there's something I don't know about
the corelibs Foundation implementation.

Will Field-Thompson

···

On Tue, Sep 6, 2016 at 8:20 AM Brent Royal-Gordon via swift-evolution < swift-evolution@swift.org> wrote:

In the current Swift 3 betas, value types can now be passed into
Objective-C as opaque box objects. A couple of reviews are currently
running which tweak this bridging, exposing Optionals and
NSValue/NSNumber-compatible types in more natural ways. These are all Good
Things. I'd like to look ahead and sketch out a way this feature could
evolve further. This will not be detailed, and much or all of it may be out
of scope for Phase 1.

Firstly, I think we could make boxed value types much more usable from
Objective-C:

1. We could bridge selector calls to equivalent Swift methods, where those
methods are Objective-C-compatible (other than being on a value type). This
could actually be done dynamically if enough metadata is available.

2. We could generate a separate subclass of our box class for each bridged
Swift type. This could actually *still* be done dynamically, I believe.

3. We could permit value types to conform to @objc protocols. This would
open up several nice features to us; perhaps most importantly, a value type
could conform to NSCoding and thereby participate in Foundation's
serialization mechanisms. I suspect that at this point, the box subclasses
would have to become "real", i.e., registered at load time. (Perhaps
they're only greedily registered if they have an explicit @objc?)

4. We could explicitly declare the bridged methods, properties, and
conformances in the generated -Swift.h file, thereby making Swift value
types directly available to Objective-C, where they can be allocated,
accessed, and manipulated in boxed form.

Secondly—and separately, but relatedly—I believe a few simple changes
could liberalize the @objc-compatibility rules, permitting many more
members to be exposed to Objective-C:

1. We could run "omit needless words" in reverse when exposing Swift
methods to Objective-C. This would prevent overloads from clashing in
Objective-C, and would also have the bonus feature of producing more
idiomatic Objective-C interfaces. (Incidentally, is a change considered
source-breaking if it breaks Objective-C code, not Swift code?)

2. We could grant access to members using Swift-only type features by
allowing the Objective-C versions to have looser types than the Swift
versions, and dynamically enforcing the missing constraints instead. For
instance, a member with a complicated `where` clause might omit the clause
in its Objective-C declaration, but enforce it with a dynamic test.

3. I suspect it might be possible to expose generic types to Objective-C
with some custom class methods. For instance, a Swift type with `Key` and
`Value` type parameters might have `+classWithKey:(Class)keyClass
value:(Class)valueClass` and +`allocWithKey:(Class)keyClass
value:(Class)valueClass` methods on it.

Are these potential features of interest? If so, to what extent do they
affect binary compatibility? On the one hand, they are extensions, adding
transparency to things which are currently opaque. But on the other hand,
they will presumably involve generating type metadata.

--
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


(Joe Groff) #3

Yeah, this is definitely a direction that at least I am interested in. Letting value types conform to @objc protocols and have @objc methods would be especially empowering for Cocoa APIs. There are some subtleties—many ObjC protocols are *intended* to be class-constrained, particularly delegate protocols, and these protocols also tend to be used as weak references and other concepts that only really make sense for classes. Your point (4) also raises a question of whether Swift value types ought to be exposed to ObjC in their boxed or unboxed forms; it seems to me that there are many structs that you'd want to export back to C or ObjC as plain structs and not boxed objects. We're also still researching the backward compatibility ramifications of changing the bridging model. While at face value, these ought to be additive changes, since we're turning purportedly opaque ObjC objects into meaningful ones, and relaxing generic constraints, the fact of the matter is people can and do rely on implementation details that are supposed to be private and subject to change. I'm hopeful we can explore this model going forward, though.

-Joe

···

On Sep 6, 2016, at 5:19 AM, Brent Royal-Gordon via swift-evolution <swift-evolution@swift.org> wrote:

In the current Swift 3 betas, value types can now be passed into Objective-C as opaque box objects. A couple of reviews are currently running which tweak this bridging, exposing Optionals and NSValue/NSNumber-compatible types in more natural ways. These are all Good Things. I'd like to look ahead and sketch out a way this feature could evolve further. This will not be detailed, and much or all of it may be out of scope for Phase 1.

Firstly, I think we could make boxed value types much more usable from Objective-C:

1. We could bridge selector calls to equivalent Swift methods, where those methods are Objective-C-compatible (other than being on a value type). This could actually be done dynamically if enough metadata is available.

2. We could generate a separate subclass of our box class for each bridged Swift type. This could actually *still* be done dynamically, I believe.

3. We could permit value types to conform to @objc protocols. This would open up several nice features to us; perhaps most importantly, a value type could conform to NSCoding and thereby participate in Foundation's serialization mechanisms. I suspect that at this point, the box subclasses would have to become "real", i.e., registered at load time. (Perhaps they're only greedily registered if they have an explicit @objc?)

4. We could explicitly declare the bridged methods, properties, and conformances in the generated -Swift.h file, thereby making Swift value types directly available to Objective-C, where they can be allocated, accessed, and manipulated in boxed form.

Secondly—and separately, but relatedly—I believe a few simple changes could liberalize the @objc-compatibility rules, permitting many more members to be exposed to Objective-C:

1. We could run "omit needless words" in reverse when exposing Swift methods to Objective-C. This would prevent overloads from clashing in Objective-C, and would also have the bonus feature of producing more idiomatic Objective-C interfaces. (Incidentally, is a change considered source-breaking if it breaks Objective-C code, not Swift code?)

2. We could grant access to members using Swift-only type features by allowing the Objective-C versions to have looser types than the Swift versions, and dynamically enforcing the missing constraints instead. For instance, a member with a complicated `where` clause might omit the clause in its Objective-C declaration, but enforce it with a dynamic test.

3. I suspect it might be possible to expose generic types to Objective-C with some custom class methods. For instance, a Swift type with `Key` and `Value` type parameters might have `+classWithKey:(Class)keyClass value:(Class)valueClass` and +`allocWithKey:(Class)keyClass value:(Class)valueClass` methods on it.

Are these potential features of interest? If so, to what extent do they affect binary compatibility? On the one hand, they are extensions, adding transparency to things which are currently opaque. But on the other hand, they will presumably involve generating type metadata.


(Brent Royal-Gordon) #4

I do hope that it will *also* become possible to access a Swift type in pure Swift given a name and a protocol it conforms to, which would allow Corelibs Foundation to also support NSCoding on value types. But that's a separate issue from improving Objective-C bridging.

···

On Sep 6, 2016, at 10:02 AM, Will Field-Thompson <will.a.ft@gmail.com> wrote:

I would rather see a Swift-centric rethinking of serialization than having the runtime dynamically register Objective-C classes anytime I want to serialize something. Plus, that seems like it's leaving Linux users out in the cold for serialization — although I'm primarily a macOS/iOS user, so maybe there's something I don't know about the corelibs Foundation implementation.

--
Brent Royal-Gordon
Architechies