What types cannot be cast to `AnyObject` in Swift 4? - swift

I've experimented with casting many types to AnyObject. Reference types obviously cast unaltered, but others are automagically converted under the hood to NSNumber, NSValue, and so on. (These are not the exact types, but close enough.) I was even able to cast a tuple successfully.
This surprised me. Are there any types that cannot be cast to AnyObject?
There are other questions and answers that may cover this material, but none of them asks this question specifically and the answer to this question can only be found in the fine print of the other answers.

AnyObject is Objective-C id, meaning any class type. Casting to AnyObject means "wrap this up in a way that Objective-C can deal with as a class type."
Obviously, an NSObject subclass just crosses the bridge directly.
For other types (i.e. nonclasses), Swift 4 follows three policies:
Some types are bridged directly to classes, e.g. String to NSString.
Some types are wrapped in Objective-C class types, e.g. Int in NSNumber or CGRect in NSValue.
All other types are boxed in an opaque wrapper; they can cross the bridge to Objective-C, and can be round-tripped successfully back to Swift, but nothing useful can be done with them in the Objective-C world.

Related

How does `NSAttibutedString` equate attribute values of type `Any`?

The enumerateAttribute(_:in:options:using:) method of NSAttributedString appears to equate arbitrary instances of type Any. Of course, Any does not conform to Equatable, so that should not be possible.
Question: How does the method compare one instance of Any to another?
Context: In Swift, I am subclassing NSTextStorage, and have need to provide my own implementation of this method in Swift.
Observations:
NSAttributedString attributes come in key-value pairs, with the keys being instances of type NSAttributedString.Key and the values being instances of type Any?, with each pair being associated with one or more ranges of characters in the string. At least, that is how the data structure appears from the outside; the internal implementation is opaque.
The enumerateAttribute method walks through the entire range of an NSAttributedString, effectively identifying each different value corresponding to a specified key, and with the ranges over which that value applies.
The values corresponding to a given key could be of multiple different types.
NSAttributedString seemingly has no way of knowing what underlying types the Any values might be, and thus seemingly no way of type casting in order to make a comparison of two given Any values.
Yet, the method somehow is differentiating among ranges of the string based on differences in the Any values.
Interestingly, the method is able to differentiate between values even when the underlying type does not conform to Equatable. I take this to be a clue that the method may be using some sort of reflection to perform the comparison.
Even more interesting, the method goes so far as to differentiate between values when the underlying type does conform to Equatable and the difference between two values is a difference that the specific implementation of Equatable intentionally ignores. In other words, even if a == b returns true, if there is a difference in opaque properties of a and b that are ignored by ==, the method will treat the values as being different, not the same.
I assume the method bridges to an implementation in ObjC.
Is the answer: It cannot be done in Swift?
As you know, Cocoa is Objective-C, so these are Objective-C NSDictionary objects, not Swift Dictionary objects. So equality comparison between them uses Objective-C isEqual, not Swift ==. We are not bound by Swift strict typing, the Equatable protocol, or anything else from Swift.
To illustrate, here's a slow and stupid but effective implementation of style run detection:
let s = NSMutableAttributedString(
string: "howdy", attributes: [.foregroundColor:UIColor.red])
s.addAttributes([.foregroundColor:UIColor.blue],
range: NSRange(location: 2, length: 1))
var lastatt = s.attributes(at: 0, effectiveRange: nil)
for ix in 1..<5 {
let newatt = s.attributes(at:ix, effectiveRange:nil)
if !(newatt as NSDictionary).isEqual(to: lastatt) {
print("style run ended at \(ix)")
lastatt = newatt
}
}
That correctly prints:
style run ended at 2
style run ended at 3
So since it is always possible to compare the attributes at any index with the attributes at another, it is possible to implement attribute enumeration in Swift. (Whether that's a good idea is another question.)

Metatype of Metatype

In Swift we are able to write following construction:
class SomeClass {}
let metaMetatype: SomeClass.Type.Type = SomeClass.Type.self
Here metaMetatype does not conform to type AnyObject (SomeClass.Type does). Construction can be even longer, as long as we wish:
let uberMetatype: SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.Type = SomeClass.Type.Type.Type.Type.Type.Type.Type.Type.Type.self
Are this constructions have any sense? If SomeClass.Type.Type not an object, what is this, and why we able to declare it?
If SomeClass.Type.Type not an object, what is this and why we able to declare it?
I will try to dissect what you're asking.
SomeClass.Type.Type is a Metatype of a Metatype. Metatypes exist in Swift because Swift has types that are not classes. This is most similar to the Metaclass concept in Objective-C.
Lexicon.rst in the Swift Open Source Repo has a pretty good explanation:
metatype
The type of a value representing a type. Greg Parker has a good
explanation of Objective-C's "metaclasses" because Swift has types
that are not classes, a more general term is used.
We also sometimes refer to a value representing a type as a "metatype
object" or just "metatype", usually within low-level contexts like IRGen
and LLDB. This is technically incorrect (it's just a "type object"), but
the malapropism happened early in the project and has stuck around.
Why are we able to declare a type of a type of a type... and so on? Because it's a feature of the language called type metadata:
type metadata
The runtime representation of a type, and everything you can do with it.
Like a Class in Objective-C, but for any type.
Note that you can't do something like NSObject().class in Swift because class is a reserved keyword for the creation of a class. This is how you would get the type (or class in this case) of an NSObject in Swift:
let nsObj = NSObject()
nsObj.classForCoder // NSObject.Type
nsObj.classForKeyedArchiver // NSObject.Type
nsObj.dynamicType // NSObject.Type
Note that nsObj and nsObj.self are identical and represent the instance of that NSObject.
I don't see where in the Swift module or open source repo where types allow for .Type, but I'm still looking. It might have to do with the inheritance from SwiftObject, the Objective-C object all Swift classes inherit from (at least on Mac).
Type of a class is also represented in memory (it has for example their own methods). It's represented by singleton representing the Type. (It's not an instance of this type - that's something different). If you call self on a Type like this SomeClass.self you will take singleton instance representing the SomeClass Type.
For more info check this answer

Custom literal method with LiteralConvertible

I am reading about LiteralConvertible protocols (lets take StringLiteralConvertible for example), and I found that in swift 1.2 you can use implicit typecasting from literal to your custom LiteralConvertible type. Following example taken from NSHipster blog:
struct SomeStruct: StringLiteralConvertible {
init(stringLiteral value: String) {}
init(extendedGraphemeClusterLiteral value: String) {}
init(unicodeScalarLiteral value: String) {}
func someFunc(){}
}
Somewhere in executable space:
let someStruct: SomeStruct = "😀"
someStruct.someFunc() // ok
("😃" as SomeStruct).someFunc() // ok
"😂" is SomeStruct // ok (always true warn)
"😡".someFunc() // error: value of type 'String' has no member 'someFunc'
Comments are for swift 2 compiler. Seems like there was no error in swift 1.2. Am I missing something or there is no way to achieve this behavior in swift 2?
It wouldn't make sense, w.r.t. type safety and non-ambiguity, if the last row ("😡".someFunc()) could resolve to just any kind of type that happens to conform to StringLiteralConvertible and have instance an function someFunc {}. Protocols cannot know (without explicit testing) which types conform to them, but rather, are used e.g. as type constraint to test if a given type conforms to the protocol. What if we have another type SomeStruct2: StringLiteralConvertible { ... } that also implements someFunc(), how would the compiler resolve the call "😡".someFunc() if the implicit type conversion you describe were to to be allowed?
W.r.t. to the concept working in Swift 1.2: Swift 1.2 is ancient in terms of a fast growing (up) language as Swift, so there are bound to be some peculiarities in Swift 1.2 that seems really strange in term of "modern Swift". Just as custom conversion methods (__conversion() function), implicit typecasting is a concept that is not entirely agreeable with a statically typed and safe language such as Swift.
To somewhat base this answer on official sources, we may take a look at Swift evolution proposal SE-0072:
SE-0072: Fully eliminate implicit bridging conversions from Swift
This proposal relates to the implicit bridging between Swift native and Obj-C types, but the Swift team's position w.r.t. to any implicit conversions is made quite clear in the description of the accepted proposal [emphasis mine]
In Swift 1.2, we attempted to remove all implicit bridging conversions
from the language.
...
In the interest of further simplifying our type system and our user
model, we would like to complete this work and fully remove implicit
bridging conversions from the language in Swift 3.
...
I propose that we fully eliminate implicit bridging conversions in
Swift 3. This would mean that some users might have to introduce more
explicit casts in their code, but we would remove another special case
from Swift's type system and be able to further simplify the compiler.

Are Int, String etc. considered to be 'primitives' in Swift?

Types representing numbers, characters and strings implemented using structures in swift.
An excerpt from the official documentation:
Data types that are normally considered basic or primitive in other
languages—such as types that represent numbers, characters, and
strings—are actually named types, defined and implemented in the Swift
standard library using structures.
Does that mean the following:
Int
Float
String
// etc
... are not considered as primitives?
Yes and no...
As other answers have noted, in Swift there's no difference at the language level between the things one thinks of as "primitives" in other languages and the other struct types in the standard library or the value types you can create yourself. For example, it's not like Java, where there's a big difference between int and Integer and it's not possible to create your own types that behave semantically like the former. In Swift, all types are "non-primitive" or "user-level": the language features that define the syntax and semantics of, say, Int are no different from those defining CGRect or UIScrollView or your own types.
However, there is still a distinction. A CPU has native instructions for tasks like adding integers, multiplying floats, and even taking vector cross products, but not those like insetting rects or searching lists. One of the things people talk about when they name some of a language's types "primitively" is that those are the types for which the compiler provides hooks into the underlying CPU architecture, so that the things you do with those types map directly to basic CPU instructions. (That is, so operations like "add two integers" don't get bogged down in object lookups and function calls.)
Swift still has that distinction — certain standard library types like Int and Float are special in that they map to basic CPU operations. (And in Swift, the compiler doesn't offer any other means to directly access those operations.)
The difference with many other languages is that for Swift, the distinction between "primitive" types and otherwise is an implementation detail of the standard library, not a "feature" of the language.
Just to ramble on this subject some more...
When people talk about strings being a "primitive" type in many languages, that's a different meaning of the word — strings are a level of abstraction further away from the CPU than integers and floats.
Strings being "primitive" in other languages usually means something like it does in C or Java: The compiler has a special case where putting something in quotes results in some data getting built into the program binary, and the place in the code where you wrote that getting a pointer to that data, possibly wrapped in some sort of object interface so you can do useful text processing with it. (That is, a string literal.) Maybe the compiler also has special cases so that you can have handy shortcuts for some of those text processing procedures, like + for concatenation.
In Swift, String is "primitive" in that it's the standard string type used by all text-related functions in the standard library. But there's no compiler magic keeping you from making your own string types that can be created with literals or handled with operators. So again, there's much less difference between "primitives" and user types in Swift.
Swift does not have primitive types.
In all programming languages, we have basic types that are available part of the language. In swift, we have these types availed through the Swift standard library, created using structures. These include the types for numbers, characters and strings.
No, they're not primitives in the sense other languages define primitives. But they behave just like primitives, in the sense that they're passed by value. This is consequence from the fact that they're internally implemented by structs. Consider:
import Foundation
struct ByValueType {
var x: Int = 0;
}
class ByReferenceType {
var x: Int = 0;
}
var str: String = "no value";
var byRef: ByReferenceType = ByReferenceType();
var byVal: ByValueType = ByValueType();
func foo(var type: ByValueType) {
type.x = 10;
}
func foo(var type: ByReferenceType) {
type.x = 10;
}
func foo(var type: String) {
type = "foo was here";
}
foo(byRef);
foo(byVal);
foo(str);
print(byRef.x);
print(byVal.x);
print(str);
The output is
10
0
no value
Just like Ruby, Swift does not have primitive types.
Int per example is implemented as structand conforms with the protocols:
BitwiseOperationsType
CVarArgType
Comparable
CustomStringConvertible
Equatable
Hashable
MirrorPathType
RandomAccessIndexType
SignedIntegerType
SignedNumberType
You can check the source code of Bool.swift where Bool is implemented.
There are no primitives in Swift.
However, there is a distinction between "value types" and "reference types". Which doesn't quite fit with either C++ or Java use.
They are partial primitive.
Swift not exposing the primitive like other language(Java). But Int, Int16, Float, Double are defined using structure which behaves like derived primitives data type(Structure) not an object pointer.
Swift Documentation favouring to primitive feature :
1.They have Hashable extension say
Axiom: x == y implies x.hashValue == y.hashValue.
and hashValue is current assigned value.
2.Most of the init method are used for type casting and overflow check (remember swift is type safe).
Int.init(_ other: Float)
3. See the below code Int have default value 0 with optional type. While NSNumber print nil with optional type variable.
var myInteger:Int? = Int.init()
print(myInteger) //Optional(0)
var myNumber:NSNumber? = NSNumber.init()
print(myNumber) //nil
Swift Documentation not favouring to primitive feature :
As per doc, There are two types: named types and compound types. No concept of primitives types.
Int support extension
extension Int : Hashable {}
All these types available through the Swift standard library not like standard keyword.

any is not identical to anyObject

I've a payload getting shuttled from one part of the system to the other.
The shuttle is carrying the payload as Any, so I could carry any kind of objects including non objects like tuples, etc.
one of the parts of the system is accepting AnyObject so is the error.
I'm confused like what type to use to carry stuff around so it's compatible between all parts of the system.
Shall I make a choice and stick to one of the types, either Any or AnyObject for the system as a whole or what's the best choice for shuttling items if you are not concerned with their actual types.
we had type Object in other languages that could carry anything around, but not sure how this works in SWIFT world
or is there a casting that could work between the two? If I'm 100% convinced that the coming object is AnyObject, I could load it off from the shuttle (Any) as an AnyObject
Note to negative voters: Please help to clear up the question if it doesn't make any sense to you or help to improve this question, since I'm new to SWIFT. I need an answer not your vote.
Edit
a case where I had to do comparison between Any and AnyObject while unit testing, how would you handle such situation.
class Test {
var name: String = "test"
}
var anyObject: AnyObject = Test()
var any: Any = anyObject
//XCTAssert(any == anyObject, "Expecting them to be equal")
any == anyObject
Any will hold any kind of type, including structs and enums as well as classes. AnyObject will only hold classes. So what Any can store is a superset of what AnyObject can. No amount of casting will cram your custom structs or enums into an AnyObject.
Sometimes it seems like AnyObject is holding a struct such as a String, but it isn’t, what has happened is somewhere along the way Swift has converted your String to an NSString (which is a class so can be stored in an AnyObject).
(technically, Any is defined as something that implements 0 or more protocols, which anything does, whereas AnyObject is defined as a special protocol all classes implicitly conform to, and that is marked as an #objc protocol, so only classes can conform to it)
edit: to answer your question about comparisons – there’s no == operator for Any or AnyObject (how would it work if you equated an Any containing a String to an Any containing an Int?). You have to cast both sides back into what they really are before you can compare them using an appropriately-defined operator for that type.