Generic Method Override Not Working in Swift

Generic method override not working in swift

Yes. But the answer is a bit weird. The first part makes a decent amount of sense; the second part is just totally weird. Let's walk through it.

struct Generic<T> {
var args: T
func display() {
print(Printer.print(args))
}
}

The correct overload to choose for print is decided at compile time, not runtime. This is the thing that confuses people the most. They want to treat Swift like JavaScript where everything is dynamic. Swift likes to be static because then it can make sure your types are right and it can do lots of optimizations (and Swift loves to do compiler optimizations). So, compile time, what type is args? Well, it's T. Is T known to be Printable? No it is not. So it uses the non-Printable version.

But when Swift specializes Generic using PrintableObj, doesn't it know at that point that it's Printable? Couldn't the compiler create a different version of display at that point? Yes, if we knew at compile time every caller that would ever exist of this function, and that none of them would ever be extended to be Printable (which could happen in a completely different module). It's hard to solve this without creating lots of weird corner cases (where internal things behave differently than public things for instance), and without forcing Swift to proactively generate every possible version of display that might be required by some future caller. Swift may improve in time, but this is a hard problem I think. (Swift already suffers some performance reductions so that public generics can be specialized without access to the original source code. This would make that problem even more complicated.)

OK, so we get that. T isn't Printable. But what if we had a type that was unambiguously Printable that we knew at compile time and lived inside this function? Would it work then?

func display() {
if let p = args as? Printable {
print(Printer.print(p))
} else {
print(Printer.print(args))
}
}

Oh so close... but not quite. This almost works. The if-let actually does exactly what you want it to do. p gets assigned. It's Printable. But it still calls the non-Printable function. ?!?!?!?!

This is a place I personally think that Swift is just currently broken and have high hopes it will be fixed. It might even be a bug. The problem is that Printable itself does not conform to Printable. Yeah, I don't get it either, but there you go. So we need to make something that does conform to Printable in order to get the right overload. As usual, type erasers to the rescue.

struct AnyPrintable: Printable {
let value: Printable
}

struct Generic<T> {
var args: T

func display() {
if let p = args as? Printable {
print(Printer.print(AnyPrintable(value: p)))
} else {
print(Printer.print(args))
}
}
}

And this will print the way you wanted. (On the assumption that Printable requires some methods, you'd just add those methods to the AnyPrintable type eraser.)

Of course the right answer is not to use generic overloads this way in Printer. It's just way too confusing and fragile. It looks so nice, but it blows up all the time.

Overriding a generic function produce an error

Just remove <T> in function. Because you have T in typealias.

protocol BaseCellProtocol {
associatedtype T
func configure(with object: T?)
}

class BaseTableViewCell: UITableViewCell, BaseCellProtocol {

typealias T = String

func configure(with object: T?) {
}
}

class TableViewCell: BaseTableViewCell {

override func configure(with object: String?) {
label.text = object
}
}

error when having class method in a generic class with same name as non-generic super class

You cannot override the function since the parameter types are difference, hence, one function cannot act as the other. Also, you cannot use the same method signature, if it already exists. The only solution is to change the name, or use the same type for the parameter as the superclass. Also, you cannot hide methods in superclasses, but you could throw an exception if it is used by overriding it.



Related Topics



Leave a reply



Submit