> 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

Reply via email to