Swift protocol allows unimplemented function when it exists in base class - swift

Assume the below playground:
protocol MyProtocol
{
func MyFunc()
}
class MyBase : MyProtocol
{
func MyFunc()
{
}
}
class MyClass : MyBase, MyProtocol
{
}
I was expecting this to not compile, and nag about not implementing my protocol. But unlike other languages, Swift seems to think its fine if the protocol conforms to the base class.
How can I get MyClass to force my method to be overridden?
I'm using Swift 1.1, tia.

Your code is definitely valid. MyClass inherits from MyBase which already conforms to MyProtocol, so having the subclass also conform to it is completely redundant. That being said, you are basically looking for an abstract function which does not really exist in Swift, the closest I think you can get to achieving what you want is recommended in this answer. So in your base class just give a warning if not overriden:
class MyBase : MyProtocol {
func MyFunc() {
fatalError("This method must be overridden")
}
}
As recommended in the question comments, a different approach may work better for what you are attempting to do (e.g. composition or using a struct), but it is a bit hard to recommend a different solution without knowing more about what you are trying to achieve (rather than just the expected solution). If you do provide additional details you may receive a more suitable answer.

Related

Method ... in non-final class ... cannot be implemented in a protocol extension because it returns 'Self' and has associated type requirements

This is my code:
protocol Person {
associatedtype Homework
static func generate(homeWork: Homework) -> Self
}
extension Person {
static func generate(homeWork: Homework) -> Self {
fatalError()
}
}
// Method 'generate(homeWork:)' in non-final class 'Teacher'
// cannot be implemented in a protocol extension because it
// returns 'Self' and has associated type requirements
class Teacher: Person {
typealias Homework = Int
}
Despite the strange naming of types, I am curious why it isn't possible to conform a non-final class to a protocol which has a method that returns Self and having a associatedtype as parameter type.
Note: I am not asking how to fix this problem (because I can just mark my class final). I want to know why this isn't possible.
I think it is strange. Protocols with associatedtypes and Self is always a struggle ofcourse, but when using one of two (returning Self/associatedtype protocol type in parameter) compiles the code just fine.
Why can't I conform to a protocol which has a default implementation of a method whereas the method has a return type of Self and associatedtype in a parameter, but when only using one of them the code compiles? Why is both a problem when dealing with inherence (because marking the class as final fixes the error message, so it has to be something with inherence)?
Looks like its because of a compiler limitation. Here's some relevant discussion from people on the Swift team:
https://twitter.com/_danielhall/status/737782965116141568
The original tweet shows what would happen if we tried to create a subclass from Teacher, the compiler would not be able to identify it as conforming to the Person protocol.
Specifically relevant from the swift team in that thread: "we don't support subtyping when matching protocol requirements. I consider it a missing feature in the language"
So knowing the compiler can't recognize subclasses as conforming to the protocol in these situations they decide to force a final class.

swift subclasses used in generics don't get called when inheriting from NSObject

Partial Solution Update at the end!
Attached is code that produces odd behavior. I copied it out of a swift playground so it should run in one fine.
I created a subclass in my project and passed it to my generic class as the concrete type. However, I quickly noticed that only the base class methods are called. This is shown with myBase and mySub below. Despite the generic class being instantiated as <mySub>, only the base methods are called. The print lines for the subclass are never shown.
Well, I found a simple way around that and that is to not inherit from NSObject. When I used swift native classes, the subclass methods are in fact called. These are secondBase and secondSub.
How do I pass a subclass into a generic class and get the actual subclass to receive calls when inheriting from NSObject?
And why would behavior be different?
import Foundation
// The Protocol
protocol P {
init ()
func doWork() -> String
}
// Generic Class
class G<T: P> {
func doThing() -> String {
let thing = T()
return thing.doWork()
}
}
// NSObject Base Class with Protocol
class A1: NSObject, P {
override required init() {
super.init()
}
func doWork() -> String {
return "A1"
}
}
// NSObject Sub Class
class B1: A1 {
required init() {
super.init()
}
override func doWork() -> String {
return "B1"
}
}
// Swift Base Class
class A2: P {
required init() {
}
func doWork() -> String {
return "A2"
}
}
// Swift Sub Class
class B2: A2 {
required init() {
super.init()
}
override func doWork() -> String {
return "B2"
}
}
print ("Sub class failure with NSObject")
print ("Recieved: " + G<B1>().doThing() + " Expected: B1 - NSObject Sub Class Generic (FAILS)")
print ("\nSub class success with Swift Native")
print ("Recieved: " + G<B2>().doThing() + " Expected: B2 - Swift Sub Class Generic (SUCCEEDS)")
print("")
#if swift(>=5.0)
print("Hello, Swift 5.0")
#elseif swift(>=4.1)
print("Hello, Swift 4.1")
#elseif swift(>=4.0)
print("Hello, Swift 4.0")
#elseif swift(>=3.0)
print("Hello, Swift 3.x")
#else
print("Hello, Swift 2.2")
#endif
Output:
Sub class failure with NSObject
Recieved: A1 Expected: B1 - NSObject Sub Class Generic (FAILS)
Sub class success with Swift Native
Recieved: B2 Expected: B2 - Swift Sub Class Generic (SUCCEEDS)
Hello, Swift 5.0
Partial solution update:
Moving the protocol conformance from the base class to the sub class allows the sub class to behave correctly. Definitions become:
class A1: NSObject
class B1: A1, P
The problem is the base class can no longer be used directly at all when no functionality beyond it is needed. This is mostly an issue if the protocol being conformed to has an associated type. When this is true, you must have a concrete class that conforms to the protocol for use in generics.
One use case here is expecting a base class in the generics (with a protocol involving an associated type) which allows something to function without caring what actual sub class was passed in. This actually ends up being a poor man's form of type erasure in some cases. And you can still use the same generic with the subclass.
G<A1>()
G<B1>()
This was derived from a similar question here: Generic Class does not forward delegate calls to concrete subclass
Partial options are:
remove NSObject and use swift native classes only
when NSObject is required, try to separate protocol conformance from inheritance of NSObject
UPDATE ON THE BELOW IDEA: Doesn't Work
I am going to test if providing an additional layer changes the behavior. Basically have 3 layers, Base class inheriting from NSObject, base Protocol class adding the protocol but inheriting from base and then specific classes. If it can distinguish between the base protocol class and the specific subclass in that case, that would be a functional workaround in all use cases. (and may explain why Apple's NSManagedObject works fine)
Still seems like a bug though.
I was able to confirm your results and submitted it as a bug, https://bugs.swift.org/browse/SR-10617. Turns out this is a known issue! I was informed (by good old Hamish) that I was duplicating https://bugs.swift.org/browse/SR-10285.
In my bug submission, I created a clean compact reduction of your example, suitable for sending to Apple:
protocol P {
init()
func doThing()
}
class Wrapper<T:P> {
func go() {
T().doThing()
}
}
class A : NSObject, P {
required override init() {}
func doThing() {
print("A")
}
}
class B : A {
required override init() {}
override func doThing() {
print("B")
}
}
Wrapper<B>().go()
On Xcode 9.2, we get "B". On Xcode 10.2, we get "A". That alone is enough to warrant a bug report.
In my report I listed three ways to work around the issue, all of which confirm that this is a bug (because none of them should make any difference):
make the generic parameterized type's constraint be A instead of P
or, mark the protocol P as #objc
or, don't have A inherit from NSObject
UPDATE: And it turns out (from Apple's own release notes) there's yet another way:
mark A's init as #nonobjc
This is not an answer so much as a way to avoid the problem.
In most of my code, I did not have to conform to NSObjectProtocol only Equatable and/or Hashable. I have implemented those protocols on the objects that needed it.
I then went through my code, removed all NSObject inheritance except on those classes which inherit from an Apple protocol or object that requires it (Like UITableViewDataSource).
The classes that are required to inherit from NSObject are Generic but they are not typically handed into other Generic classes. Therefore the inheritance works fine. In my MVVM pattern these tend to be the intermediate classes that work with view controllers to make logic like table views reusable. I have a tableController class that conforms to the UITableView protocols and accepts 3 generic viewModel types allowing it to provide the table logic for 95% of my views with no modifications. And when it needs it, subclasses easily provide alternate logic.
This is a better strategy as I am no longer randomly using NSObject for no reason.
This is a second way to avoid the problem.
#matt originally suggested this but then deleted his answer. It is a good way to avoid the problem. His answer was simple. Mark the protocol with objc like this:
// The Protocol
#objc protocol P {
init ()
func doWork() -> String
}
This solves the above sample code and you now get the expected results. But doing this has side effects for swift. At least one of those is here:
How to use #objc protocol with optional and extensions at the same time?
For me, it began a chain of having to make all my protocols objc compatible. That made the change not worth it for my code base. I was also using extensions.
I decided to stay with my original answer at least until Apple fixes this bug or there is a less invasive solution.
I thought this one should be documented in case it helps someone else facing this problem.

Inheritance in Class Vs Protocol

I am little bit messed up with the following concept:
Code 1 :
class New{
func abc(){
print("new class")
}
}
class ClassNew: New {
override func abc() {
print("derived class")
}
}
Code 2:
protocol New{}
extension New{
func abc(){
print("new protocol")
}
}
class ClassNew: New {
func abc() {
print("derived protocol")
}
}
What is the difference between Code 1 and Code 2 as both of them serves the same purpose?
In code 2, classNew is inheriting from new protocol or just conforming to the protocol?
Any Explanation will be highly appreciated!
Code 1 and code 2 are fundamentally not the same.
What is the difference between Code 1 and Code 2 as both of them serves the same purpose?
No they don't. The first one defines a class hierarchy, the second defines a protocol (an API, if you like) and a type that conforms to it.
In code 2, classNew is inheriting from new protocol or just conforming to the protocol?
It's conforming to the protocol. There's no inheritance involved (if you are being pedantic).
Code 1 defines a base class and a class that inherits from it. The subclass overrides the base class for the function abc() and it behaves as you would expect given a class hierarchy i.e.
let x: New = ClassNew()
let y: ClassNew = ClassNew()
print(x.abc()) // prints "derived class"
print(y.abc()) // prints "derived class"
Both print statements call the derived class's abc()
In code 2 you define a protocol with no methods, and an extension to the protocol with an extension method. Note that this is not a "default method" there is nothing in the protocol to default. You then define a class that conforms to the protocol and adds a new method that happens to have the same name as the extension method. The distinction (from the pure class hierarchy) is important because the version of abc() called is determined statically at compile time
protocol New2{}
extension New2{
func abc(){
print("new protocol")
}
}
class ClassNew2: New2 {
func abc() {
print("derived protocol")
}
}
let y2: ClassNew2 = ClassNew2()
let x2: New2 = y2
print(x2.abc()) // prints "new protocol"
print(y2.abc()) // prints "derived protocol"
Even though x2 and y2 are the same object different versions of the function are called. This is because the compiler is not allowed to assume anything about x2 except what it can infer from the protocol. So it doesn't know that the object has anabc() of its own so it must call the extension function.
If you had defined the protocol like this:
protocol New3{
func abc()
}
extension New3{
func abc(){
print("new protocol")
}
}
class ClassNew3: New3 {
func abc() {
print("derived protocol")
}
}
let y3: ClassNew3 = ClassNew3()
let x3: New3 = y3
print(x3.abc()) // prints "derived protocol"
print(y3.abc()) // prints "derived protocol"
This time the compiler knows that the object should have a function abc() and will only use the extension function if it doesn't. Then the normal inheritance rules for classes apply.
Code 2 is an example of protocol extensions. Big difference is that you can't call super.abc() in Code 2 — you have to provide a method implementation that is not in any super context.
Just my opinion — do not use protocol default implementation, as compiler won't save you if you forget to provide "override" when you really need one.
classNew is simply conforming to the protocol in the second code. This is true to every protocol in Swift as inheritance is not currently supported with protocols.
This also answers your first question: there is no significant difference between the two codes in this use case, but, generally speaking, a protocol is good for other kinds of things than subclassing.
Code 1 and Code 2 are exactly same, just conceptually different.
If we put it in simple words, a Class defines the object itself, and a Protocol defines the behaviour of the object.
If compared to Java, a protocol is similar to Interfaces.
Checkout the Protocol Documentation

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.

Ambiguous func in two protocols

I think it might be just a rare situation, but how can I deal with the same (ambiguous) function from two different protocol. For example, I have these defines:
protocol A {
func foo()
func bar() -> Int
}
protocol B {
func foo()
func bar() -> String
}
Now I have a class conforms A and B. Can I implement different versions of foo() for A and B separately. If I can do so, how can I call them?
P.S. I know for bar(), I can use something like this to make a call:
let anInt = (instance as A).bar()
let aString = (instance as B).bar()
Is it possible to do similar thing on foo() function?
No. The point of a protocol is that it requires that an object provide a particular method, but the method is not "tied" to the protocol. That's why you can use extensions to cause existing classes to conform to new protocols using their existing methods.
As a note, this sounds like a mistake in the protocol design. Having two protocols require different semantics for the same method name suggests that the method is incorrectly named.