> On Dec 12, 2016, at 12:12 PM, Charles Srstka via swift-evolution
> <[email protected]> wrote:
>
> I’ve been trying to figure out the rationale for why the code below behaves
> the way it does for some time:
>
> import Foundation
>
> class C: NSObject {
> dynamic var foo: Int { return 5 }
> dynamic func bar() -> Int { return 6 }
> }
>
> struct S {}
>
> let c = C()
> let s = S()
>
> print(c is AnyObject) // warning: 'is' test is always true
> print(s is AnyObject) // warning: 'is' test is always true (?!)
>
> print(c as AnyObject) // <Project.C: 0x0123456789012345>
> print(s as AnyObject) // Project.S()
>
> print(c as? AnyObject) // warning: conditional cast from 'C' to 'AnyObject'
> always succeeds
> print(s as? AnyObject) // warning: conditional cast from 'S' to 'AnyObject'
> always succeeds
>
> print(c as AnyObject? as Any) // Optional(<Project.C: 0x0123456789012345>)
> print(s as AnyObject? as Any) // Optional(Project.S())
>
> print((c as AnyObject?)?.foo as Any) // Optional(5)
> print((s as AnyObject?)?.foo as Any) // nil
> print((c as AnyObject?)?.bar() as Any) // Optional(6)
> print((s as AnyObject?)?.bar() as Any) // crash! -[_SwiftValue bar]:
> unrecognized selector sent to instance 0x5432109876543210
>
> So what we have is:
>
> 1. Any type you have will always claim it’s a class type, every time, even if
> it’s actually a non-bridgeable value type.
>
> 2. Conditional casting will also succeed, even if you use it on a
> non-bridgeable value type.
>
> 3. Non-conditional casting works too, despite that the underlying type might
> be a non-bridgeable value type.
>
> 4. Bridging to an optional will *also* always give you a value, even if
> what’s underneath is a non-bridgeable value type.
>
> 5. Trying to call a property on an optional from #4 will, surprisingly, work
> as you’d expect. The class type that implements the property returns the
> property, the value type returns nil.
>
> 6. Trying to call a method on an optional from #4 will crash.
>
> This raises a few questions:
>
> 1. Why in the blazes is it implemented like this? Why not only allow
> conditional casting to AnyObject, which would only succeed if the type either
> actually was an object or could actually be bridged to an object? Why make
> the cast guaranteed, even when in actuality it’s not?
Everything *can* be bridged to an object as a result of SE-0116 ("id-as-Any"),
so there's no longer such a thing as a "non-bridgable value type". #6 is a bug,
since the AnyObject method lookup ought to produce `nil` if the ObjC method
isn't implemented on the object.
> 2. Why is there no obvious way to figure out whether something can actually
> be an object? The already kind of non-obvious “type(of: s) is AnyObject.Type”
> trick works to tell you if the thing is already a class, but not if something
> is bridgeable to a class; using it on a string, for example, returns false.
> And trying something like “type(of: s as AnyObject) is AnyObject.Type”
> returns true (?!), so that doesn’t work to detect bridgeable things.
What are you trying to do that requires you to know whether something is a
class or bridgable to a class (which, as mentioned above, includes everything)?
-Joe
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution