Why does the protocol default value passed to the function not change, even though the function does when subclassing? - swift

I have a protocol, to which I have assigned some default values:
protocol HigherProtocol {
var level: Int { get }
func doSomething()
}
extension HigherProtocol {
var level: Int { 10 }
func doSomething() {
print("Higher level is \(level)")
}
}
Then I have another protocol which conforms to the higher level protocol, but has different default values and implementation of functions:
protocol LowerProtocol: HigherProtocol {}
extension LowerProtocol {
var level: Int { 1 }
func doSomething() {
print("Lower level is \(level)")
}
}
I then create a class that conforms to the HigherProtocol, and then a subclass that conforms to the lower level protocol:
class HigherClass: HigherProtocol {}
class LowerClass: HigherClass, LowerProtocol {}
When I instantiate this lower class, however, it displays some odd behaviour:
let lowerClass = LowerClass()
lowerClass.level // is 1
lowerClass.doSomething() // Prints "Lower level is 10" to the console.
The default property is correct, but the default implementation of the function seems to be a hybrid of the two.
I'm wondering what's happening here?

You appear to be trying to use protocols to create multiple-inheritance. They're not designed for that, and even if you get this working, you're going to get bitten several times. Protocols are not a replacement for inheritance, multiple or otherwise. (As a rule, Swift favors composition rather than inheritance in any form.)
The problem here is that HigherClass conforms to HigherProtocol and so now has implementations for level and doSomething. LowerClass inherits from that, and wants to override those implementations. But the overrides are in a protocol extension, which is undefined behavior. See Extensions from The Swift Programming Language:
Extensions can add new functionality to a type, but they cannot override existing functionality.
Undefined behavior doesn't mean "it doesn't override." It means "anything could happen" including this weird case where it sometimes is overridden and sometimes isn't.
(As a side note, the situation is similar in Objective-C. Implementing a method in two different categories makes it undefined which one is called, and there's no warning or error to let you when this happens. Swift's optimizations can make the behavior even more surprising.)
I wish the compiler could detect these kinds of mistakes and raise an error, but it doesn't. You'll need to redesign your system to not do this.

Protocols are existential types that is why you are confused. You need to expose to protocol types of your class Type. In your case you can do LowerProtocol or HigherProtocol so it prints 10 now. Let`s make like this
let lowerClass: LowerProtocol = LowerClass()
or
let lowerClass: HigherProtocol = LowerClass()
lowerClass.level // now prints 10
lowerClass.doSomething() // Prints "Lower level is 10" to the console.

Related

Strange behavior with Swift generics and protocol extensions

I'm seeing some strange behavior at the interface of protocol extensions and generics. I'm new to Swift, so possibly I misunderstand, but I don't see how this can be correct behavior.
First let's define a protocol, and extend it with a default function implementation:
protocol Foo {
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
Now define a couple of conforming types:
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
A.yo()
B.yo()
As expected, A.yo() uses the default implementation of yo, whereas B.yo() uses the explicit implementation provided by B: the output is
Foo.yo
B.yo
Now let's make a simple generic type:
struct C<T: Foo> {
static func what() {
T.yo()
}
}
C<A>.what()
C<B>.what()
C<A>.what() prints Foo.yo, as expected. But C<B>.what() also prints Foo.yo!
Surely the meaning of C<B> is simply the template for C with B substituted in for the type parameter T? Yet B's version of yo is not being called.
What am I missing? I'm using Swift 5.2.2.
Now, as it turns out you can fix this problem by declaring yo in the original definition of Foo. If we do this:
protocol Foo {
static func yo()
}
then C<B>.what() works as I would expect, printing B.yo. I can't understand the original behavior in the first place, but even less can I understand how this would change it.
In my actual application I can't use this fix, because I am extending a pre-existing protocol with a function that I want to specialize in a particular conforming type.
Generics are resolved at compile time. They're not dynamically dispatched like method calls on class hierarchies or protocols. That staticness is kind of their point, that's where the performance wins stem from.
As far as I can tell, Foo.yo() and B.yo() are totally unrelated functions. Calling Foo.yo() does a statically dispatched call to Foo, and likewise, calling B.yo() causes a statically dispatched call to B.
Yet, if you up-cast B.self to a Foo.Type, and you call yo() on it, you end up with a statically dispatched call to Foo:
(B.self as Foo.Type).yo()
To get dynamic dispatch (to achieve the kind of polymorphism you're after), you need to define yo as a requirement of the protocol. That establishes a relationship between B.yo() (which is now a part of the conformance to the protocol) and Foo.yo() (which is a default implementation for types who don't provide their own).
protocol Foo {
// static func yo() // uncomment this
}
extension Foo {
static func yo() {
print("Foo.yo")
}
}
struct A: Foo {
}
struct B: Foo {
static func yo() {
print("B.yo")
}
}
struct C<T: Foo> {
static func what() {
T.yo()
}
}
A.yo()
B.yo()
(B.self as Foo.Type).yo()
C<A>.what()
C<B>.what()
Results before:
Foo.yo
B.yo
Foo.yo
Foo.yo
Foo.yo
Results after making yo a requirement:
Foo.yo
B.yo
B.yo
Foo.yo
B.yo
It’s hard to suggest a fix for your exact situation without more details of the exact situation- are you not able to provide these? Suffice to say this is the expected behaviour and its to do with some optimisations and assumptions the compiler makes.
You might want to check out this article on static vs dynamic dispatch in Swift: https://medium.com/#PavloShadov/https-medium-com-pavloshadov-swift-protocols-magic-of-dynamic-static-methods-dispatches-dfe0e0c85509

Cannot convert swift generic subclass to generic superclass

I want to write better and cleaner code using parametrized classes in Swift but I'm getting a strange build error:
Cannot convert value of type 'CustomAdapter' to expected argument type 'TableTestParametrizedAdapter<ETableViewCell>'
What I actually want is to be able to create a base adapter class with one method (overridden in adapter subclasses) used to bind cell subclasses with the corresponding data model and get rid of casting every time.
I'll post the code below, in order to understand better what I mean.
class TestParametrizedAdapter<C>: NSObject {
func doSmth(cell: C) {
}
}
class TableTestParametrizedAdapter<C>: TestParametrizedAdapter<C> where C:ETableViewCell {
}
class PeopleTableViewCell: ETableViewCell {
}
class CustomAdapter: TableTestParametrizedAdapter<PeopleTableViewCell> {
override func doSmth(cell: PeopleTableViewCell) {
}
}
class TestBaseController: UIViewController {
var adapter: TableTestParametrizedAdapter<ETableViewCell>?
override func viewDidLoad() {
super.viewDidLoad()
setAdapter(adapter: CustomAdapter()) // this is the line with build error
}
func setAdapter(adapter: TableTestParametrizedAdapter<ETableViewCell>) {
self.adapter = adapter
}
}
I have read on some other posts about this and there was pointed out that GenericClass<B> and GenericClass<A> are completely unrelated even if B is a subclass of A, hence you cannot cast one to the other. (https://stackoverflow.com/a/50859053/10115072)
Anywat, are there any solutions for this? How can we use the power of parametrization of Swift in this case? I use Swift 4.
Thanks in advance.
Even if Swift would support variance in custom generics your code would be wrong, since you try to use object that can only handle PeopleTableViewCell instances in place of object that can handle any ETableViewCell. If that is indeed what you want and you don't mind some run-time checks you can do something similar with little type erasure:
class TestAnyAdapter: NSObject {
func doSmth(cell: Any) {}
}
class TableTestParametrizedAdapter<C>: TestAnyAdapter where C:ETableViewCell {
override func doSmth(cell: Any) {
guard let cell = cell as? C else {
return
}
self.doSmth(cell: cell)
}
func doSmth(cell: C) {}
}
the rest of the code will be the same as you already have, only without compile-time error.
I agree with Konstantin about the fundamental problem here. This code is simply incorrect, and Swift is telling you so. CustomAdapter.doSmth cannot accept any arbitrary ETableViewCell, but adapter claims it must.
There are many solutions, depending on the actual problem you're trying to solve. You indicated you want to write "better and cleaner code." That suggests you have existing code where you're finding excessive duplication or casting. So what you want to do is look at that code, and see what code is being duplicated, and then we can help you design generic solutions to avoid that duplication. There is no universal answer to this question; abstraction choices you make in one direction will make other directions less flexible. Abstraction is choices; they need to be made in context.
As a rule in Swift, you should avoid relying on subclassing. There is some that is required, because of bridging to ObjC, but Swift-focused code should avoid subclasses. In your particular example, the interesting class has just one function. If that's really true, then implementing it is easy. Use one function:
func customAdapter(cell: PeopleTableViewCell) {}
class TestBaseController: UIViewController {
let adapter: (PeopleTableViewCell) -> Void = customAdapter
}
"But my real problem is more complex than that!" Ok. Then we have to talk about your real problem. Abstracting these things down to their simplest forms rightly should lead to the simplest solutions. If things are actually a bit more complex, you could use a struct and a protocol.
protocol Adapter {
associatedtype Cell: UITableViewCell
func doSmth(cell: Cell)
}
struct CustomAdapter<Cell: ETableViewCell>: Adapter {
func doSmth(cell: Cell) {}
}
class TestBaseController: UIViewController {
let adapter: CustomAdapter<PeopleTableViewCell> = CustomAdapter()
}
I'm glossing over what may be your question, which is how to make a function that only accepts PeopleTableViewCell be used where a function that accepts any ETableViewCell is required. That's impossible. It's not a limitation in Swift; it's just type-wise impossible. The best you could do is add "do nothing" or "crash" as Konstantin explains.
If you can nail down a little more what particular problem in your existing code you're trying to fix, we can probably help you design better solutions. Adding generics does not make your code "better or cleaner" by themselves (and most of the best solutions barely need generics at all in my experience).
Let's try to get some facts straight.
Let's say we have generic class C<T>.
And let's also say we have classes D and D2, where D2 is the subclass of T.
Then C<D2> is not a subclass of C<D>. They are just separate types. (We say there is not covariance.)
Let's say our generic class C<T> has a subclass C2<T>.
Then C2<D> is a subclass of C<D>, and C2<D2> is a subclass of C<D2>.
So as long as the parameterized types are the same, there's polymorphism. But there's no covariance if the parameterized types are different, even if parameterized types are class and subclass.
(Swift Optional and Swift collections get a special covariance dispensation here, but that's baked into the language; you can't the same dispensation.)

Swift: Is it possible to add a protocol extension to a protocol?

Lets say I have two protocols:
protocol TheirPcol {}
protocol MyPcol {
func extraFunc()
}
What I want to do is to create a protocol extension for 'TheirPcol' which lets extraFunc() work on anything which conforms to 'TheirPcol'. So something like this:
extension TheirPcol : MyPcol { // Error 'Extension of protocol 'TheirPcol' cannot have an inheritance clause.
func extraFunc() { /* do magic */}
}
struct TheirStruct:TheirPcol {}
let inst = TheirStruct()
inst.extraFunc()
The kicker in this is that 'TheirPcol', 'TheirStruct' are all handled by an external API which I do not control. So I'm passed the instance 'inst'.
Can this be done? Or am I going to have to do something like this:
struct TheirStruct:TheirPcol {}
let inst = TheirStruct() as! MyPcol
inst.extraFunc()
It seems there are two use-cases of why you may want to do what you are doing. In the first use-case, Swift will allow you to do what you want, but not very cleanly in the second use-case. I'm guessing you fall into the second category, but I'll go through both.
Extending the functionality of TheirPcol
One reason why you might want to do this is simply to give extra functionality to TheirPcol. Just like the compiler error says, you cannot extend Swift protocols to conform to other protocols. However, you can simply extend TheirPcol.
extension TheirPcol {
func extraFunc() { /* do magic */ }
}
Here, you are giving all objects that conform to TheirPcol the method extraFunc() and giving it a default implementation. This accomplishes the task of extending functionality for the objects conforming to TheirPcol, and if you want it to apply to your own objects as well then you could conform your objects to TheirPcol. In many situations, however, you want to keep MyPcol as your primary protocol and just treat TheirPcol as conforming to MyPcol. Unfortunately, Swift does not currently support protocol extensions declaring conformance to other protocols.
Using TheirPcol objects as if they were MyPcol
In the use case (most likely your use case) where you really do need the separate existence of MyPcol, then as far as I am aware there is no clean way to do what you want yet. Here's a few working but non-ideal solutions:
Wrapper around TheirPcol
One potentially messy approach would be to have a struct or class like the following:
struct TheirPcolWrapper<T: TheirPcol>: MyPcol {
var object: T
func extraFunc() { /* Do magic using object */ }
}
You could theoretically use this struct as an alternative to casting, as in your example, when you need to make an existing object instance conform to MyPcol. Or, if you have functions that accept MyPcol as a generic parameter, you could create equivalent functions that take in TheirPcol, then convert it to TheirPcolWrapper and send it off to the other function taking in MyPcol.
Another thing to note is if you are being passed an object of TheirPcol, then you won't be able to create a TheirPcolWrapper instance without first casting it down to an explicit type. This is due to some generics limitations of Swift. So, an object like this could be an alternative:
struct TheirPcolWrapper: MyPcol {
var object: MyPcol
func extraFunc() { /* Do magic using object */ }
}
This would mean you could create a TheirPcolWrapper instance without knowing the explicit type of the TheirPcol you are given.
For a large project, though, both of these could get messy really fast.
Extending individual objects using a child protocol
Yet another non-ideal solution is to extend each object that you know conforms to TheirPcol and that you know you wish to support. For example, suppose you know that ObjectA and ObjectB conform to TheirPcol. You could create a child protocol of MyPcol and then explicitly declare conformance for both objects, as below:
protocol BridgedToMyPcol: TheirPcol, MyPcol {}
extension BridgedToMyPcol {
func extraFunc() {
// Do magic here, given that the object is guaranteed to conform to TheirPcol
}
}
extension ObjectA: BridgedToMyPcol {}
extension ObjectB: BridgedToMyPcol {}
Unfortunately, this approach breaks down if there are a large number of objects that you wish to support, or if you cannot know ahead of time what the objects will be. It also becomes a problem when you don't know the explicit type of a TheirPcol you are given, although you can use type(of:) to get a metatype.
A note about Swift 4
You should check out Conditional conformances, a proposal accepted for inclusion in Swift 4. Specifically, this proposal outlines the ability to have the following extension:
extension Array: Equatable where Element: Equatable {
static func ==(lhs: Array<Element>, rhs: Array<Element>) -> Bool { ... }
}
While this is not quite what you are asking, at the bottom you'll find "Alternatives considered", which has a sub-section called "Extending protocols to conform to protocols", which is much more what you're trying to do. It provides the following example:
extension Collection: Equatable where Iterator.Element: Equatable {
static func ==(lhs: Self, rhs: Self) -> Bool {
// ...
}
}
Then states the following:
This protocol extension would make any Collection of Equatable elements Equatable, which is a powerful feature that could be put to good use. Introducing conditional conformances for protocol extensions would exacerbate the problem of overlapping conformances, because it would be unreasonable to say that the existence of the above protocol extension means that no type that conforms to Collection could declare its own conformance to Equatable, conditional or otherwise.
While I realize you're not asking for the ability to have conditional conformances, this is the closest thing I could find regarding discussion of protocols being extended to conform to other protocols.

Difference between using Generic and Protocol as type parameters, what are the pros and cons of implement them in a function

Since Swift allows us using both Protocol and Generic as parameter types in a function, the scenario below has come into my mind:
protocol AProtocol {
var name: String{ get }
}
class ClassA: AProtocol {
var name = "Allen"
}
func printNameGeneric<T: AProtocol>(param: T) {
print(param.name)
}
func printNameProtocol(param: AProtocol) {
print(param.name)
}
The first function uses generic as parameter type with a type constraint, and the second function uses protocol as the parameter type directly. However, these two functions can have the same effect, which is the point confusing me. So my questions are:
What are the specific scenarios for each of them (or a case which can only be done by the specific one, but not another)?
For the given case, both functions turn out the same result. Which one is better to implement (or the pros and cons of each of them)?
This great talk has mentioned generic specialization, which is a optimization that turn the way of function dispatching from dynamic dispatching (function with non-generic parameters) to static dispatching or inlining (function with generic parameters). Since static dispatching and inlining are less expensive in contrast with dynamic dispatching, to implement functions with generic can always provide a better performance.
#Hamish also gave great information in this post, have a look for more information.
Here is a new question came to me:
struct StructA: AProtocol {
var a: Int
}
struct StructB: AProtocol {
var b: Int
}
func buttonClicked(sender: UIButton) {
var aVar: AProtocol
if sender == self.buttonA
{
aVar = StructA(a: 1)
}
else if sender == self.buttonA
{
aVar = StructB(b: 2)
}
foo(param: aVar)
}
func foo<T: AProtocol>(param: T) {
//do something
}
If there are several types conform to a Protocol, and are pass in to a generic function in different conditions dynamically. As shown above, pressing different buttons will pass different types(StructA or StructB) of parameter into function, would the generic specialization still work in this case?
There is actually a video from this year's WWDC about that (it was about performance of classes, structs and protocols; I don't have a link but you should be able to find it).
In your second function, where you pass a any value that conforms to that protocol, you are actually passing a container that has 24 bytes of storage for the passed value, and 16 bytes for type related information (to determine which methods to call, ergo dynamic dispatch). If the passed value is now bigger than 24 bytes in memory, the object will be allocated on the heap and the container stores a reference to that object! That is actually extremely time consuming and should certainly be avoided if possible.
In your first function, where you use a generic constraint, there is actually created another function by the compiler that explicitly performs the function's operations upon that type. (If you use this function with lots of different types, your code size may, however, increase significantly; see C++ code bloat for further reference.) However, the compiler can now statically dispatch the methods, inline the function if possible and does certainly not have to allocate any heap space. Stated in the video mentioned above, code size does not have to increase significantly as code can still be shared... so the function with generic constraint is certainly the way to go!
Now we have two protocol below:
protocol A {
func sometingA()
}
protocol B {
func sometingB()
}
Then the parameter need to conform to both A and B.
//Generic solution
func methodGeneric<T:A>(t:T)where T:B {
t.sometingA()
t.sometingB()
}
//we need protocol C to define the parameter type
protocol C:A,B {}
//Protocol solution
func methodProtocol(c:C){
c.sometingA()
c.sometingB()
}
It seems that nothing is wrong but when we define a struct like this:
struct S:A,B {
func sometingB() {
print("B")
}
func sometingA() {
print("A")
}
}
The methodGeneric works but we need to change struct S:A,B to struct S:C to make methodProtocol work. Some questions:
Do we really need protocol C?
Why not would we write like func method(s:S)?
You could read more about this in the Generic Doc for additional information .

Can a Swift class be extended multiple times with the same methods?

I am designing a framework that uses protocols and extensions to allow for third-parties to add support for my framework to their existing classes.
I'd also like to include some built-in extensions for known classes like UIView, but I don't want to prevent users from defining their own additional support for the same classes.
My question is is there any way that I can extend the same class twice, and override the same (protocol) method in that class both times, while still having some way to call the other if the first one fails.
Elaboration: I really have three goals here I want to achieve:
I want to allow users of my framework to provide their own extensions for their own (or any) UIView subclasses.
I also need some way to allow general behavior that can apply to all UIViews as a fallback option (i.e. if the specific class extension can't handle it, fall back on the generic UIView extension).
I'd also like to separate out my own implementation, by providing some built-in generic view handling, but in such a way that it doesn't prevent third parties from also defining their own additional generic handling. (If I can't do this, it's not a big deal, the first two parts are the most important.)
I have part 1 working already. The problem is how to get this fallback behavior implemented. If I do it all with extensions, the subclass will override the superclass's implementation of the protocol method. It could call super.method, but I'd like to avoid putting that responsibility on the subclass (in case the author forgets to call super).
I'd like to do this all from the framework code: first, call the object's protocol method. If it returns false, I'd like to somehow call the generic UIView handler.
Now that I'm typing it all out, I'm wondering if I can just use a different method for the generic fallback and be done with it. I just figured it would be elegant if I could do it all with one method.
No! It can't be extended multiple times.
extension Int {
var add: Int {return self + 100} // Line A
}
extension Int {
var add: Int {return self + 105} //Line B
}
Doing so would create a compile time error ( on Line B) indicating: Invalid redeclaration of 'add'
Swift is a static typing language and helps you find these sorts of errors before runtime
In Objective-C you can write this and still not get an error, however the result would be undefined, because you wouldn't know which method gets loaded first during runtime.
Overriding a single protocol method twice in 2 separate extensions wouldn't work, because the protocol method names would collide. Once compiled, they're all just methods on the same class. With that in mind, perhaps put all the protocol methods in their own extension & call them from within the other ones?
The following could be one general option. Could get messy if you decide to keep adding additional extension functionality.
class baseClass {
//stuff
}
extension baseClass: myProtocol {
override func myProtocolMethod(args) -> returnType {
//Repeat this in a separate extension & your method names collide
var status: Bool
//protocol method code sets status as appropriate...
return status = true ? optOne(status) : optTwo(status)
}
func optOne(status:Bool) -> returnType{
//do the 'true' thing
return returnType
}
func optTwo(status:Bool) -> returnType{
//do the 'false' thing
return returnType
}
}
extension baseClass {
var oneExtension = myProtocolMethod(someArg)
}
extension baseClass {
var twoExtension = myProtocolMethod(someArg)
}
I realize this Question is over a year old and the original poster has probably moved on to other things, but I'd like to share an idea anyways and perhaps get some feedback.
You say that you want a method that can be overwritten multiple times. The short answer, like many in this thread have given is no, but the long answer is yes.
We can solve the issue with a bit of generic magic.
class MyView: UIView {
var customizer: MyProtocol<MyView> = Defaults()
func willCallCustomizer() {
customizer.coolMethod(self)
}
}
// Use this class as if it were a protocol
class MyProtocol<T: UIView>: NSObject {
func coolMethod(_ view: T) {}
}
// Class inherits from the "protocol"
class Defaults: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// Some default behavior
}
}
/// on the clients end...
class CustomerCustomizer: MyProtocol<MyView> {
override func coolMethod(_ view: MyView) {
// customized behavior
}
}
So if the client wants to use their own customizer they can just set it, otherwise it will just use the default one.
myViewInstance.customizer = CustomerCustomizer()
The benefit of this approach is that the client can change the customizer object as many times as they want. Because MyProtocol is generic, it may be used for other UIView's as well; thus fulfilling the role of a protocol.