At runtime, how does Swift know which implementation to use? - swift

protocol A {
func f()
}
struct S1 : A {
func f() {
print("S1")
}
}
struct S2 : A {
func f() {
print("S2")
}
}
let array: [A] = [S1(), S2()]
for s: A in array {
s.f()
}
// "S1\n" "S2\n"
If this was an inheritance hierarchy, I would expect Swift to use a v-table to look up the correct implementation. However, the concrete types in array could be anything that implements A, along with any number of other protocols, so how would the Swift runtime know the structure of the object if it was also using v-tables?

The Swift runtime uses a Protocol Witness Table which holds pointers to each type's implementations of the protocol methods.
Mike Ash explains it best in his article Exploring Swift Memory Layout, Part II:
The last one, at offset 32 is a "protocol witness table" for the underlying type and the protocol, which contains pointers to the type's implementations of the protocol methods. This is how the compiler is able to invoke methods, such as p(), on a value of protocol type without knowing the underlying type at runtime.
I would also watch the WWDC video Understanding Swift Performance as suggested in the comments by Hamish.

Related

How to allow a generic collection to perform under the hood conversion in swift

I am implementing a generic collection and I would like to make its usage with types/protocol hierarchy more convenient. I stumbled on the following question.
How one does implement a collection
class SpecialSet<ObjectType> {
Such that given two types B : A one can perform implicite conversion of SpecialSet<B> into SpecialSet<A> ?
I am suprised but I wasn't able to find any documentation explaining this simple concept that indeed exist for the Array collection. This swift code is indeed valid:
let b = [B(), B(), B()]
let a: [A] = b
I probably do not used the right vocabulary in my searches.
I tried to define a constructor as follow but it seams not possible to enforce inheritance between two generic.
init<T>(_ specialSet: SpecialSet<T>) where T: ObjectType {
It has always been impossible.
Swift generics are normally invariant, but the Swift standard library
collection types — even though those types appear to be regular
generic types — use some sort of magic inaccessible to mere mortals
that lets them be covariant.
Potential workaround. 🤷‍♂️
protocol Subclass: AnyObject {
associatedtype Superclass
}
extension B: Subclass {
typealias Superclass = A
}
class SpecialSet<Object>: ExpressibleByArrayLiteral {
required init(arrayLiteral _: Object...) { }
init<T: Subclass>(_: SpecialSet<T>) where T.Superclass == Object { }
}
let specialSetB: SpecialSet = [B(), B()]
let specialSetA = SpecialSet<A>(specialSetB)

Nesting structs in Protocol Extension: Type '...' cannot be nested in generic function '...()'

I have a protocol, let's say Fruit (see below).
Within one of the methods I want to use a custom struct.
This results in the following error:
Type 'Packet' cannot be nested in generic function 'saveObject()'
Why is this not allowed?
protocol Fruit: Codable
{
var vitamines: Int { get }
var description: String { get }
}
extension Fruit
{
func saveObject()
{
struct Packet
{
let val1, val2, val3: Int
}
let packet = Packet(val1: vitamines, val2: 0, val3: 0)
}
}
Looking for a solution or viable alternatives.
I've tried using a tuple but I need to save the Packet to Data, which is not easily possible using a tuple (as far as I know).
You cannot nest new types inside of generic structures in extensions this way. Allowing that would likely become very complex, since it is not quite clear whether this type would be Fruit.saveObject.Packet or <ConformingType>.saveObject.Packet. For example, consider the following (legal) code for how these kinds of types can escape, and the system has to deal with them, including knowing how to dispatch methods to them, how much storage they require, etc.
protocol P {}
func x() -> P {
struct T: P {}
return T()
}
type(of: x())
If you change this to make x() generic, then it is no longer legal:
func x<Y>() -> P {
struct T: P {} // error: type 'T' cannot be nested in generic function 'x()'
return T()
}
That said, if you believe that the language should be changed to allow this, then Swift Evolution is the process to suggest it. You should first think though how you would like this to work if Fruit had associatedtypes, if saveObject() were itself generic, and if Packet included reference to type variable defined in either of those places. (I'm not saying these are insurmountable problems at all. This may be an excellent feature and it may be possible to design it very well. You just need to think through how it interacts with other features of the language.)
The solution is to move Packet to the top level, outside the extension and outside the protocol.

How to do Type erasure in Swift using if-let?

I see many articles on type-erasure. But most of their examples focus on putting different types into an array.
Is there any way I can get this code to work?
protocol A {
associatedtype Data
func printThis(value: Data)
}
class B {
}
let x = B()
if let y = x as? A { // I get error on this line
// Do nothing
}
Xcode error states
Protocol 'A' can only be used as a generic constraint because it has Self or associated type requirements
This example code is just for demonstration purposes.
As of Swift 4, protocols that have associated type requirements can only be used as generic constraints in function declarations, as in:
func foo<T: A>(t: T) where A.Data: Whatever { ... }
Unless you remove the associated type from the protocol, you cannot just type variables to it; you can only use it to define a generic type.
If Swift ever gains the ability to have generalized existentials in the future, then this may change. But for the time being, this just isn't possible in Swift.

Why don't protocols in Swift use brackets instead of associated types? [duplicate]

I'm confused about the difference between the syntax used for associated types for protocols, on the one hand, and generic types on the other.
In Swift, for example, one can define a generic type using something like
struct Stack<T> {
var items = [T]()
mutating func push(item: T) {
items.append(item)
}
mutating func pop() -> T {
return items.removeLast()
}
}
while one defines a protocol with associated types using something like
protocol Container {
associatedtype T
mutating func append(item: T)
var count: Int { get }
subscript(i: Int) -> T { get }
}
Why isn't the latter just:
protocol Container<T> {
mutating func append(item: T)
var count: Int { get }
subscript(i: Int) -> T { get }
}
Is there some deep (or perhaps just obvious and lost on me) reason that the language hasn't adopted the latter syntax?
RobNapier's answer is (as usual) quite good, but just for an alternate perspective that might prove further enlightening...
On Associated Types
A protocol is an abstract set of requirements — a checklist that a concrete type must fulfill in order to say it conforms to the protocol. Traditionally one thinks of that checklist of being behaviors: methods or properties implemented by the concrete type. Associated types are a way of naming the things that are involved in such a checklist, and thereby expanding the definition while keeping it open-ended as to how a conforming type implements conformance.
When you see:
protocol SimpleSetType {
associatedtype Element
func insert(_ element: Element)
func contains(_ element: Element) -> Bool
// ...
}
What that means is that, for a type to claim conformance to SimpleSetType, not only must that type contain insert(_:) and contains(_:) functions, those two functions must take the same type of parameter as each other. But it doesn't matter what the type of that parameter is.
You can implement this protocol with a generic or non-generic type:
class BagOfBytes: SimpleSetType {
func insert(_ byte: UInt8) { /*...*/ }
func contains(_ byte: UInt8) -> Bool { /*...*/ }
}
struct SetOfEquatables<T: Equatable>: SimpleSetType {
func insert(_ item: T) { /*...*/ }
func contains(_ item: T) -> Bool { /*...*/ }
}
Notice that nowhere does BagOfBytes or SetOfEquatables define the connection between SimpleSetType.Element and the type used as the parameter for their two methods — the compiler automagically works out that those types are associated with the right methods, so they meet the protocol's requirement for an associated type.
On Generic Type Parameters
Where associated types expand your vocabulary for creating abstract checklists, generic type parameters restrict the implementation of a concrete type. When you have a generic class like this:
class ViewController<V: View> {
var view: V
}
It doesn't say that there are lots of different ways to make a ViewController (as long as you have a view), it says a ViewController is a real, concrete thing, and it has a view. And furthermore, we don't know exactly what kind of view any given ViewController instance has, but we do know that it must be a View (either a subclass of the View class, or a type implementing the View protocol... we don't say).
Or to put it another way, writing a generic type or function is sort of a shortcut for writing actual code. Take this example:
func allEqual<T: Equatable>(a: T, b: T, c: T) {
return a == b && b == c
}
This has the same effect as if you went through all the Equatable types and wrote:
func allEqual(a: Int, b: Int, c: Int) { return a == b && b == c }
func allEqual(a: String, b: String, c: String) { return a == b && b == c }
func allEqual(a: Samophlange, b: Samophlange, c: Samophlange) { return a == b && b == c }
As you can see, we're creating code here, implementing new behavior — much unlike with protocol associated types where we're only describing the requirements for something else to fulfill.
TLDR
Associated types and generic type parameters are very different kinds of tools: associated types are a language of description, and generics are a language of implementation. They have very different purposes, even though their uses sometimes look similar (especially when it comes to subtle-at-first-glance differences like that between an abstract blueprint for collections of any element type, and an actual collection type that can still have any generic element). Because they're very different beasts, they have different syntax.
Further reading
The Swift team has a nice writeup on generics, protocols, and related features here.
This has been covered a few times on the devlist. The basic answer is that associated types are more flexible than type parameters. While you have a specific case here of one type parameter, it is quite possible to have several. For instance, Collections have an Element type, but also an Index type and a Generator type. If you specialized them entirely with type parameterization, you'd have to talk about things like Array<String, Int, Generator<String>> or the like. (This would allow me to create arrays that were subscripted by something other than Int, which could be considered a feature, but also adds a lot of complexity.)
It's possible to skip all that (Java does), but then you have fewer ways that you can constrain your types. Java in fact is pretty limited in how it can constrain types. You can't have an arbitrary indexing type on your collections in Java. Scala extends the Java type system with associated types just like Swift. Associated types have been incredibly powerful in Scala. They are also a regular source of confusion and hair-tearing.
Whether this extra power is worth it is a completely different question, and only time will tell. But associated types definitely are more powerful than simple type parameterization.
To add to the already great answers, there's another big difference between generics and associated types: the direction of the type generic fulfilment.
In case of generic types, it's the client that dictates which type should be used for the generic, while in case of protocols with associated types that's totally in the control of the type itself. Which means that types that conform to associated types are in liberty to choose the associated type that suits them best, instead of being forced to work with some types they don't know about.
As others have said, the Collection protocol is a good example of why associated types are more fit in some cases. The protocol looks like this (note that I omitted some of the other associated types):
protocol Collection {
associatedtype Element
associatedtype Index
...
}
If the protocol would've been defined as Collection<Element, Index>, then this would've put a great burden on the type conforming to Collection, as it would've have to support any kind of indexing, many of them which don't even make sense (e.g. indexing by a UIApplication value).
So, choosing the associated types road for protocol generics it's also a matter of empowering the type that conforms to that protocol, since it's that type the one that dictates what happens with the generics. And yes, that might sound less flexible, but if you think about it all types that conform to Collection are generic types, however they only allow generics for the types that make sense (i.e. Element), while "hardcoding" the other associated types (e.g. Index) to types that make sense and are usable in their context.

Using some protocol as a concrete type conforming to another protocol is not supported

I’m trying to mix generics with protocols and I’m getting a really hard time xD
I have certain architecture implemented in an Android/Java project, and I’m trying to rewrite it to fit it in a swift/iOS project. But I’ve found this limitation.
ProtocolA
protocol ProtocolA {
}
ProtocolB
protocol ProtocolB : ProtocolA {
}
ImplementProtocolA
class ImplementProtocolA <P : ProtocolA> {
let currentProtocol : P
init(currentProtocol : P) {
self.currentProtocol = currentProtocol
}
}
ImplementProtocolB
class ImplementProtocolB : ImplementProtocolA<ProtocolB> {
}
So, when I try to set ProtocolB as the concrete type that implements ProtocolA, I get this error:
Using 'ProtocolB' as a concrete type conforming to protocol 'ProtocolA' is not supported
1 Is there any reason for this “limitation”?
2 Is there any workaround to get this implemented?
3 Will it be supported at some point?
--UPDATED--
Another variant of the same problem, I think:
View protocols
protocol View {
}
protocol GetUserView : View {
func showProgress()
func hideProgress()
func showError(message:String)
func showUser(userDemo:UserDemo)
}
Presenter protocols
protocol Presenter {
typealias V : View
}
class UserDemoPresenter : Presenter {
typealias V = GetUserView
}
Error:
UserDemoPresenter.swift Possibly intended match 'V' (aka
'GetUserView') does not conform to 'View’
What is that?? It conforms!
Even if I use View instead of GetUserView, it does not compile.
class UserDemoPresenter : Presenter {
typealias V = View
}
UserDemoPresenter.swift Possibly intended match 'V' (aka 'View') does
not conform to 'View'
xxDD I don’t get it, really.
--UPDATED--
With the solution proposed by Rob Napier the problem is not fixed, instead, it is just delayed.
When a try to define a reference to UserDemoPresenter, I need to specify the generic type, so I get the same error:
private var presenter : UserDemoPresenter<GetUserView>
Using 'GetUserView' as a concrete type conforming to protocol
'GetUserView' is not supported
The underlying reason for the limitation is that Swift doesn't have first-class metatypes. The simplest example is that this doesn't work:
func isEmpty(xs: Array) -> Bool {
return xs.count == 0
}
In theory, this code could work, and if it did there would be a lot of other types I could make (like Functor and Monad, which really can't be expressed in Swift today). But you can't. You need to help Swift nail this down to a concrete type. Often we do that with generics:
func isEmpty<T>(xs: [T]) -> Bool {
return xs.count == 0
}
Notice that T is totally redundant here. There is no reason I should have to express it; it's never used. But Swift requires it so it can turn the abstract Array into the concrete [T]. The same is true in your case.
This is a concrete type (well, it's an abstract type that will be turned into a concrete type any time it's instantiated and P is filled in):
class ImplementProtocolA<P : ProtocolA>
This is a fully abstract type that Swift doesn't have any rule to turn into a concrete type:
class ImplementProtocolB : ImplementProtocolA<ProtocolB>
You need to make it concrete. This will compile:
class ImplementProtocolB<T: ProtocolB> : ImplementProtocolA<T> {}
And also:
class UserDemoPresenter<T: GetUserView> : Presenter {
typealias V = T
}
Just because you're likely to run into the issue later: your life will go much easier if you'll make these structs or final classes. Mixing protocols, generics, and class polymorphism is full of very sharp edges. Sometimes you're lucky and it just won't compile. Sometimes it will call things you don't expect.
You may be interested in A Little Respect for AnySequence which details some related issues.
private var presenter : UserDemoPresenter<GetUserView>
This is still an abstract type. You mean:
final class Something<T: GetUserView> {
private var presenter: UserDemoPresenter<T>
}
If that creates a problem, you'll need to create a box. See Protocol doesn't conform to itself? for discussion of how you type-erase so that you can hold abstract types. But you need to work in concrete types. You can't ultimately specialize on a protocol. You must eventually specialize on something concrete in the majority of cases.