6

PlayingCard inherits from Card

Given the two functions with the same name:

 func match(othercards : [PlayingCard]) ->  Int {
     return 2 
 }

 func match(othercards : [Card]) ->  Int {
     return 2 
 }

It is throwing an Error Saying : Overriding method with selector 'match:' has incompatible type '([PlayingCard]) -> Int'

Why??? Its two functions with same name but two different kind of parameters why is it still asking for override?? If I do that then even that is called as Error

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
sriram hegde
  • 2,301
  • 5
  • 29
  • 43
  • Does PlayingCard inherit from Card? – bhspencer Jul 25 '15 at 17:49
  • Yes it does inherit from Card – sriram hegde Jul 25 '15 at 17:50
  • 1
    Then that is the problem – bhspencer Jul 25 '15 at 17:50
  • You write a different method name e.g. matchPlayingCard (othercards : [PlayingCard]) -> Int – bhspencer Jul 25 '15 at 17:54
  • There is a similar question here http://stackoverflow.com/questions/17944322/is-it-possible-to-override-a-method-with-a-derived-parameter-instead-of-a-base-o this is for c# but the principle is the same for Swift and Java – bhspencer Jul 25 '15 at 17:55
  • Ok Thank You! Upvote my question . :) – sriram hegde Jul 25 '15 at 17:56
  • 1
    I tried your code but I don't get the expected error (Using Xcode 6.4). Are you using 6.3.x? So try updating it. – Qbyte Jul 25 '15 at 18:19
  • You could use : if othercards.isKindOfClass(Card) do something, else do something else. – Swift Rabbit Jul 25 '15 at 18:22
  • Wait, I don't think that this is the problem. I tested it on Playground + a simple app. **If Card is a class**. And **PlayingCard is a class that extends Card** then it does **compile and run just fine**. Tested with Xcode 6.4 and Swift 1.2. – Luca Angeletti Jul 25 '15 at 18:24
  • Hmm? Weird cuz my xcode is xcode6.4 and swift is 1.2 but I havent tried this in playground ill check it out and let you know guys. Thanks Anyways! :D – sriram hegde Jul 25 '15 at 18:34
  • @appzYourLife in your running code if you call match with an instance of PlayingCard which method gets called? How could the compiler possibly know which one you want to use? – bhspencer Jul 25 '15 at 18:57
  • @bhspencer: you are right. **Overloading is done at compile time.** So here the compiler just looks at the type of the variable (not actually at the instance inside it). So this code returns 1: `let card : PlayingCard = PlayingCard() card.match([PlayingCard]())` and this code returns 2: `let card : Card = PlayingCard() card.match([PlayingCard]())` – Luca Angeletti Jul 25 '15 at 19:53

3 Answers3

2

Can you do this?

class Card {
    func match(othercards : [Card]) ->  Int {
        return 2 // I changed the return value just to test it
    }
}

class PlayingCard : Card {
    func match(othercards : [PlayingCard]) ->  Int {
        return 1
    }
}

Yes!

Specifically you can if Card does not extends NSObject.

class Card {
    func match(othercards : [Card]) ->  Int {
        return 2 // I changed the return value just to test it
    }
}

On the other hand, if Card extends NSObject.

class Card : NSObject {
    func match(othercards : [Card]) ->  Int {
        return 2 // I changed the return value just to test it
    }
}

Then you get the error!

It looks like overloading only works on "pure" Swift classes.

Luca Angeletti
  • 58,465
  • 13
  • 121
  • 148
  • 1
    You are absolutely right . it works fine if the 2 functions are declared in same class but throws error when two functions are declared in different classes that inherits from one – sriram hegde Jul 25 '15 at 18:36
  • Pls Upvote my question if you find it useful . Thank you :) – sriram hegde Jul 25 '15 at 18:40
  • I see you are changing the accepted answer. Please note that you can accept **only one answer**. So every time you accept another one, the previous one loses the "accepted mark". – Luca Angeletti Jul 25 '15 at 18:43
  • And... Someone is wondering why they just lost points-- first time it happened to me I thought I was multiple down-voted! – rholmes Jul 25 '15 at 19:03
  • Do you know why there is an error if Card extends NSObject? – bhspencer Jul 25 '15 at 19:17
  • @sriramhegde if your are putting two functions in the same class then you are overloading not overriding. Your original question is about overriding. – bhspencer Jul 25 '15 at 19:21
  • @bhspencer: I also thought they were in the same class. Intact in the first version of my answer I put both methods in the same class. Then one of the comment above made me realized that the original code was probably organized with one method for each class. So I updated the code accordingly. But it's just an assumption :) – Luca Angeletti Jul 25 '15 at 19:27
  • @bhspencer: Maybe there is an errore when `Card extends NSObject` because `Objective-C` does not support method overloading. – Luca Angeletti Jul 25 '15 at 21:13
  • The error message is not about method overloading. It is about Overriding. – bhspencer Jul 25 '15 at 23:39
1

The Swift compiler must see both PlayingCard and Card as the same type. If one inherits (either by subtype or protocol (under certain circumstances)), that could explain it.

Although it may be considered a code smell, you can also check the type at runtime, and use only one function, as in the accepted answer here: Checking if an object is a given type in Swift.

Some patterns that can be applied are given in this explanation of a similar example -- although the question is about C#, similar object oriented techniques can be applied: overriding method with derived parameter instead of base.

Community
  • 1
  • 1
rholmes
  • 4,064
  • 3
  • 25
  • 34
0

Since PlaingCard inherits from Card you are not permitted to override the method in this way.

Consider what would happen if you tried to call match with an instance of PlayingCard. Which of the two methods would it call? It would be ambiguous and so is not allowed.

In this case one solution is to change the name of the method that takes the more specific type. e.g.

 func matchPlayingCard(othercards : [PlayingCard]) ->  Int {
     return 2 
 }
bhspencer
  • 13,086
  • 5
  • 35
  • 44
  • 1
    You present it as if it is obligatorily ambiguous and it's not. The compiler could just select the nearest one up in the hierarchy. – User Jul 25 '15 at 19:14
  • I am not certain about swift but in Java this is called a covariant parameter and it is not permitted. http://www.java-tips.org/java-se-tips-100019/24-java-lang/482-covariant-parameter-types.html – bhspencer Jul 25 '15 at 21:42
  • 1
    This is overloading and doesn't have anything to do with covariance, at least in this context. The link you post is when overriding a method (or implementing interface). You actually can overload with different types of the same hierarchy in Java. Except if it's a type parameter (e.g. `List` and `List`) but that limitation comes from type erasure which doesn't exist in Swift. – User Jul 25 '15 at 21:55
  • @Ixx I agree. This is overloading and it's perfectly legal in Swift. You just have to avoid extending NSObject. – Luca Angeletti Jul 25 '15 at 22:55
  • How can this be overloading when the original question is talking about overriding? Even the error message included in the OPs question states Overriding is going on. – bhspencer Jul 25 '15 at 23:31
  • 1
    Well, we all know the current quality of error messages in Swift :) ... maybe it's caused by the internal representation or something. The code in question is clearly overloading, not overriding. – User Jul 29 '15 at 18:04