Are Int, String etc. considered to be 'primitives' in Swift? - 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.

Related

In Swift, how to get the true size of an `Any` variable?

I want to be able to get the size of the underlying data type of an Any variable in Swift. I expected this to be possible by running MemoryLayout.size(ofValue: anyObject), but that expression always returns 32, regardless of the the underlying data type of the Any object. I assume 32 is the size of the internal Any construct/type, which holds metadata about the object it stores.
How do I get the underlying data type's size?
let regularInt: Int = 1
let anyInt: Any = Int(2) as Any
MemoryLayout<Int>.size // 4
MemoryLayout<type(of: anyInt)>.size // Can't do that
MemoryLayout.size(ofValue: regularInt) // 4
MemoryLayout.size(ofValue: anyInt) // 32
// How do I get size "4" out of `anyInt`?
I'll begin with some technical details about the limitations of Any in this case.
So, what is Any? It's an empty protocol to which every type implicitly conforms to.
And how does the compiler represent variables of protocol types? It's by wrapping the actual value in an existential container. So basically when you're referencing a variable of this kind, you're actually talking to the container (well, actually not you, but the compiler is :).
An existential container has a layout that can be represented like this C structure:
struct OpaqueExistentialContainer {
void *fixedSizeBuffer[3];
Metadata *type;
WitnessTable *witnessTables[NUM_WITNESS_TABLES];
};
The container elements are greatly explained in this document, I'll also try to summarize them here:
fixedSizeBuffer either holds the whole value, if it takes less than 24 bytes, or holds a pointer to a heap allocated zone, containing the value
type is a pointer to the type metadata
witnessTables is what makes this layout occupy various sizes, as the number of protocol witness tables can vary from zero to virtually any number of protocols.
So, with the above in mind:
Any needs no witness tables, thus it occupies 32 bytes
a single protocol variable occupies 40 byes
a composed protocol variable occupies 32 + N*8, where N is the number of "independent" protocols involved in the composition
Note that the above is true if there are no class protocols involved, if a class protocol is involved, then the existential container layout is a little bit simplified, this is also better described in the linked document from above.
Now, back to the problem from the question, it's the existential container created by the compiler the one which prevents you from accessing the actual type. The compiler doesn't make this structure available, and transparently translates any calls to protocol requirements to dispatches through the witness tables stored in the container.
But, might I ask you, why are you circulating Any? I assume you don't want to handle all possible and future types in a generic manner. A marker protocol might help here:
protocol MemoryLayouted { }
extension MemoryLayouted {
var memoryLayoutSize: Int { MemoryLayout.size(ofValue: self) }
}
Then all you have left to do is to add conformance for the types you want to support:
extension Int: MemoryLayouted { }
extension String: MemoryLayouted { }
extension MyAwesomeType: MemoryLayouted { }
With the above in mind, you can rewrite your initial code to something like this:
let regularInt: Int = 1
let anyInt: MemoryLayouted = 2
print(regularInt.memoryLayoutSize) // 8
print(anyInt.memoryLayoutSize) // 8
You get consistent behaviour and type safety, a type safety that might translate to a more stable application.
P.S. A hacky approach, that allows you to use Any, might pe possible by unpacking the existential container via direct memory access. The Swift ABI is stable at this point, so the existential container layout is guaranteed not to change in the future, however not recommending going that route unless absolutely necessary.
Maybe someone that stumbles this question and has experience in the ABI layout code can provide the code for it.
What I would do is cast Any to all supported types. Why would you cast Int as Any when you know what type is it! anyway?
var value: Any = Int(2) as Any
switch value {
case value is Int:
// ... other cases here
}

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.)

Swift dynamic type checking for structs?

I'm confused about dynamic type checking in Swift.
Specifically, I have a weirdo case where I want to, essentially, write (or find) a function:
func isInstanceOf(obj: Any, type: Any.Type) -> Bool
In Objective-C, this is isKindOfClass, but that won't work because Any.Type includes Swift structs, which are not classes (much less NSObject subclasses).
I can't use Swift is here, because that requires a hardcoded type.
I can't use obj.dynamicType == type because that would ignore subclasses.
The Swift book seems to suggest that this information is lost, and not available for structs at all:
Classes have additional capabilities that structures do not:
...
Type casting enables you to check and interpret the type of a class instance at runtime.
(On the Type Casting chapter, it says "Type casting in Swift is implemented with the is and as operators", so it seems to be a broader definition of "type casting" than in other languages.)
However, it can't be true that is/as don't work with structures, since you can put Strings and Ints into an [Any], and pull them out later, and use is String or is Int to figure out what they were. The Type Casting chapter of the Swift Book does exactly this!
Is there something that's as powerful as isKindOfClass but for any Swift instances? This information still must exist at runtime, right?
Actually you can use is operator.
Use the type check operator (is) to check whether an instance is of a certain subclass type. The type check operator returns true if the instance is of that subclass type and false if it is not.
Since struct can't be subclassed, is is guaranteed to be consistent when applied to instance of struct because it will check on it static type, and for classes it will query the dynamic type in runtime.
func `is`<T>(instance: Any, of kind: T.Type) -> Bool{
return instance is T;
}
This work for both, struct and class.
As already stated, is/as should work fine with structs. Other corner cases can usually be done with generic functions, something like:
let thing: Any = "hi" as Any
func item<T: Any>(_ item: Any, isType: T.Type) -> Bool {
return (item as? T) != nil
}
print(item(thing, isType: String.self)) // prints "true"
No idea if this fits your specific use case.
More generally, keep in mind that Swift (currently) requires knowing the type of everything at compile time. If you can't define the specific type that will be passed into a function or set as a variable, neither will the compiler.

How should protocol/implementation pairs be adjusted for the Swift API design guidelines?

In the new Swift API design guidelines, the commonly-used Type suffix for protocols is being dropped. While this is easy to do for protocols that are stand-alone (SequenceType becomes Sequence), I'm not sure how to update my APIs in which a protocol provides the base for an implementation. Here's some examples from popular frameworks:
The Result µframework provides Result, a concrete success/fail enumeration, and ResultType, a generic base protocol for a success/fail type, to which Result conforms.
ReactiveCocoa's main types are Signal and SignalProducer, which are backed by SignalType and SignalProducerType.
In both cases, much of the implementation is in extensions of the protocols, allowing extensions to use the full power of type constraints, and allowing the implementations to be generic. This is different from the case of protocols with AnySequence-style type-erasing types: you aren't really expected to implement these protocols on your own, or unify disparate types.
I would advise using the suffix Protocol. This is consistent with how the standard library have stripped the Type suffix from protocols, as stated in SE-0006:
On high level, the changes can be summarized as follows.
Strip Type suffix from protocol names. In a few special cases this
means adding a Protocol suffix to get out of the way of type names
that are primary (though most of these we expect to be obsoleted by
Swift 3 language features).
For example, GeneratorType was renamed to IteratorProtocol.
And, for example, is also how both Result & ReactiveSwift have updated their APIs for Swift 3. ResultType was renamed to ResultProtocol (in this commit), and SignalType was renamed to SignalProtocol, and SignalProducerType was renamed to SignalProducerProtocol (in this commit).
Although it's worth noting that in a vast majority of these cases, such protocols only exist as a workaround for the lack of parameterised extensions.
For example, we cannot currently say:
struct SomeGenericThing<T> {
var value: T
}
extension <T> Array where Element == SomeGenericThing<T>, T : Comparable {
}
But introducing a protocol allows us to realise the generic placeholder(s) as associated type(s), which we can then use in constraints:
protocol SomeGenericThingProtocol {
associatedtype T
var value: T { get set }
}
struct SomeGenericThing<T> : SomeGenericThingProtocol {
var value: T
}
extension Array where Element : SomeGenericThingProtocol, Element.T : Comparable {
// ...
}
Therefore once parameterised extensions are supported, we'll be able to do away with such protocols.

Is there a difference between Swift 2.0 protocol extensions and Java/C# abstract classes?

With the addition of protocol extensions in Swift 2.0, it seems like protocols have basically become Java/C# abstract classes. The only difference that I can see is that abstract classes limit to single inheritance, whereas a Swift type can conform to any number of protocols.
Is this a correct understanding of protocols in Swift 2.0, or are there other differences?
There are several important differences...
Protocol extensions can work with value types as well as classes.
Value types are structs and enums. For example, you could extend IntegerArithmeticType to add an isPrime property to all integer types (UInt8, Int32, etc). Or you can combine protocol extensions with struct extensions to add the same functionality to multiple existing types — say, adding vector arithmetic support to both CGPoint and CGVector.
Java and C# don't really have user-creatable/extensible "plain old data" types at a language level, so there's not really an analogue here. Swift uses value types a lot — unlike ObjC, C#, and Java, in Swift even collections are copy-on-write value types. This helps to solve a lot of problems about mutability and thread-safety, so making your own value types instead of always using classes can help you write better code. (See Building Better Apps with Value Types in Swift from WWDC15.)
Protocol extensions can be constrained.
For example, you can have an extension that adds methods to CollectionType only when the collection's underlying element type meets some criteria. Here's one that finds the maximum element of a collection — on a collection of numbers or strings, this property shows up, but on a collection of, say, UIViews (which aren't Comparable), this property doesn't exist.
extension CollectionType where Self.Generator.Element: Comparable {
var max: Self.Generator.Element {
var best = self[self.startIndex]
for elt in self {
if elt > best {
best = elt
}
}
return best
}
}
(Hat tip: this example showed up on the excellent NSBlog just today.)
There's some more good examples of constrained protocol extensions in these WWDC15 talks (and probably more, too, but I'm not caught up on videos yet):
Protocol-Oriented Programming in Swift
Swift in Practice
Abstract classes—in whatever language, including ObjC or Swift where they're a coding convention rather than a language feature—work along class inheritance lines, so all subclasses inherit the abstract class functionality whether it makes sense or not.
Protocols can choose static or dynamic dispatch.
This one's more of a head-scratcher, but can be really powerful if used well. Here's a basic example (again from NSBlog):
protocol P {
func a()
}
extension P {
func a() { print("default implementation of A") }
func b() { print("default implementation of B") }
}
struct S: P {
func a() { print("specialized implementation of A") }
func b() { print("specialized implementation of B") }
}
let p: P = S()
p.a() // -> "specialized implementation of A"
p.b() // -> "default implementation of B"
As Apple notes in Protocol-Oriented Programming in Swift, you can use this to choose which functions should be override points that can be customized by clients that adopt a protocol, and which functions should always be standard functionality provided by the protocol.
A type can gain extension functionality from multiple protocols.
As you've noted already, protocol conformance is a form of multiple inheritance. If your type conforms to multiple protocols, and those protocols have extensions, your type gains the features of all extensions whose constraints it meets.
You might be aware of other languages that offer multiple inheritance for classes, where that opens an ugly can of worms because you don't know what can happen if you inherit from multiple classes that have the same members or functions. Swift 2 is a bit better in this regard:
Conflicts between protocol extensions are always resolved in favor of the most constrained extension. So, for example, a method on collections of views always wins over the same-named method on arbitrary collections (which in turn wins over the same-named methods on arbitrary sequences, because CollectionType is a subtype of SequenceType).
Calling an API that's otherwise conflicting is a compile error, not a runtime ambiguity.
Protocols (and extensions) can't create storage.
A protocol definition can require that types adopting the protocol must implement a property:
protocol Named {
var name: String { get } // or { get set } for readwrite
}
A type adopting the protocol can choose whether to implement that as a stored property or a computed property, but either way, the adopting type must declare its implementation the property.
An extension can implement a computed property, but an extension cannot add a stored property. This is true whether it's a protocol extension or an extension of a specific type (class, struct, or enum).
By contrast, a class can add stored properties to be used by a subclass. And while there are no language features in Swift to enforce that a superclass be abstract (that is, you can't make the compiler forbid instance creation), you can always create "abstract" superclasses informally if you want to make use of this ability.