somu
(somu)
1
Hi,
I have a doubt regarding AnyObject
Code:
struct S {}
let s1 = S()
//I thought this would throw a compilation error
//because struct doesn't conform to AnyObject
let a : AnyObject = s1 as AnyObject
Question
- Why does the above code compile without errors?
- Am I missing something?
Based on the documentation:
AnyObject can be used as the concrete type for an instance of any class, class type, or class-only protocol.
Thanks.
1 Like
somu
(somu)
3
@AlexanderM Thanks for the explanation.
I was surprised to see that my own type behaving this way (I didn't expect it to be bridged, thanks to your explanation regarding _NSSwiftValue)
Observation:
- It happens even when
Foundation is not imported. Any reason for that?
AlexanderM
(Alexander Momchilov)
4
It happens even when Foundation is not imported. Any reason for that?
struct S {}
let s = S()
let anyObject: AnyObject = s as AnyObject
print(anyObject) // => __SwiftValue
Oh no, it's metastasizing.
No idea why.
2 Likes
cukr
5
On macos gui apps Foundation is imported even if you don't import Foundation
¯\_(ツ)_/¯
1 Like
AlexanderM
(Alexander Momchilov)
6
That test above is from a raw .swift file, without even importing AppKit or any other such frameworks which indirectly import Foundation
1 Like
cukr
7
I just checked, and it even works on linux, which has no objc...
1 Like
This is a primary use case for Why isn't static checking for "can be cast" between two generic placeholders possible?
CastError(s1, desired: AnyObject.self) // .impossible
CastError(s1, undesired: AnyObject.self) // nil
Fortunately, comparisons for is AnyClass work differently than is AnyObject. Doesn't help at compile-time though.
1 Like
somu
(somu)
9
Thanks a lot @AlexanderM, @cukr and @anon9791410
Just my observation, it doesn't tell why it is happening but looks like all free bridging will satisfy is clause
struct S {}
let s1 = S()
print(s1 is AnyObject) //compiler: 'is' test is always true
import Foundation
let str : String = ""
print(str is NSString) //compiler: 'is' test is always true
Question:
So is there a way to be sure only class instances can be passed to a function (Example below)?
func f1(anyObject: AnyObject) {} //Is there any way to restrict the parameter to only class instances?
let a : AnyObject = S() as AnyObject //S is a struct
f1(anyObject: a) //valid
S() as AnyObject is not an S. It's one of these, which is a class: swift/SwiftValue.h at main · apple/swift · GitHub
You can restrict that arguments are objects, but you can't restrict that they are values. The best you have for that is something like my CastError. Which is not good enough! 
1 Like
somu
(somu)
11
Thanks a lot @Jessy,
From the header of SwiftValue
This implements the Objective-C class that is used to carry Swift values
that have been bridged to Objective-C objects without special handling.
The class is opaque to user code, but is NSObject- and NSCopying-
conforming and is understood by the Swift runtime for dynamic casting
back to the contained type.
So I suppose the reason to do it is only to pass it to Objective-C. It is like an NSObject with a type erasure (to erase NSObject type)
1 Like