How do I override methods that have associated type parameters in subclasses? - swift

What I tried to do:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: NSObject, HasElement {
typealias ItemType = Element
func getElement() -> Element { ... }
func setElement(element: Element) { ... }
}
class Bar: Foo {
typealias ItemType = BarElement
override func getElement() -> BarElement { ... } // This works.
override func setElement(element: BarElement) { ... } // This fails.
}
The error is:
Method does not override any method from its superclass
If I try to use ItemType instead:
override func setElement(element: ItemType) { ... } // Still fails.
The error is:
'ItemType' is ambiguous for type lookup in this context
Is there a way to make this work?

Here's a way to do what you want:
protocol HasElement {
associatedtype ItemType
func getElement() -> ItemType
func setElement(element: ItemType)
}
class Element {}
class BarElement: Element {}
class Foo: HasElement {
// no need for typealias, the associated type is inferred
func getElement() -> Element { return Element() }
func setElement(element: Element) { }
}
class Bar: Foo {
// no need for typealias, the associated type is inferred
override func getElement() -> BarElement { return BarElement() }
// hide the parent class method
#available(*, unavailable, message: "Use setElement(element: BarElement)")
override func setElement(element: Element) { }
// comply with protocol in this class
func setElement(element: BarElement) { }
}
// can't do this now:
let myElement = Element()
let myBar = Bar()
myBar.setElement(element: myElement) // Error: 'setElement(element: BarElement)' is unavailable: Use setElement(element: BarElement)

The problem here isn't associated types, it's that method inputs are contravariant. Therefore you cannot override a method that expects a given superclass instance input with a method that expects a subclass instance input.
In fact, you can simply boil your code down to:
class Element {}
class BarElement : Element {}
class Foo {
func setElement(element: Element) { }
}
class Bar : Foo {
// error: Method does not override any method from its superclass
override func setElement(element: BarElement) { }
}
You simply cannot override an (Element) -> Void method with a (BarElement) -> Void method. The reasons for this should be fairly obvious if you consider what would happen if you created a Bar instance and upcast it to Foo. You're now able to pass an Element instance to a method that expects a BarElement instance, which is illegal.
The reason it works for your getElement method is that method outputs are covariant. Therefore overriding a () -> Element method with a () -> BarElement method is perfectly legal, as even if you upcast a Bar instance to Foo, the BarElement instance returned from getElement can be freely upcast to Element.
As for solutions, it rather depends on your exact use case. It may well be that what you're trying to do doesn't require inheritance at all, and instead you can just conform Foo and Bar to HasElement separately.

This works:
override func getElement() -> BarElement { ... }
using override keyword is when function signature does not change (BarElement is still Element). You copy and paste function from super class with same function name, same parameter name and same return value type.
But
override func setElement(element: BarElement) { ... }
fails because when you change parameter type (with same parameter name).
This case is overloading not overriding.

Related

PAT typealias is ambiguous for type lookup in this context

In trying to subclass my base class that conforms to a PAT, I get this compiler warning:
'MyType' is ambiguous for type lookup in this context
in my code as shown below:
protocol DataSourceProtocol {
associatedtype MyType
func get () -> MyType
}
class AnyDataSource: DataSourceProtocol {
typealias MyType = EntityProtocol
func get() -> MyType { fatalError("No implementation") }
}
class DataSource_A<T: EntityProtocol & DataSource_A_Compatible>: AnyDataSource {
typealias MyType = T
override func get() -> MyType { // <-- 'MyType' is ambiguous for type lookup in this context
return T()
}
}
class DataSource_B<T: EntityProtocol & DataSource_B_Compatible>: AnyDataSource {
override func get() -> MyType {
return T()
}
}
I am trying to override the method get() -> MyType so that the DataSource_A instance method returns a specialized type T, hence typealias MyType = T
If I change the DataSource_A method to override func get -> T, the compiler says that the function does not override any method in its superclass.
In DataSource_B, the overridden method is called but provides no type information for type T because the caller receives type EntityProtocol which is not sufficient.
If I remove the function declaration in DataSourceProtocol and in the base class AnyDataSource, and simply declare it in the subclass, it works fine, but I want to make the method's implementation mandatory for any subclass of AnyDataSource.
Why can't I specify that the overridden method returns an object of type T by changing the value of MyType in the subclass?
I want to make the method's implementation mandatory for any subclass
of AnyDataSource.
The way to express that is to make AnyDataSource generic.
class AnyDataSource<Entity: EntityProtocol>: DataSourceProtocol {
func get() -> Entity { .init() }
}
class DataSource_A<Entity: EntityProtocol & DataSource_A_Compatible>: AnyDataSource<Entity> {
// override if needed
}

Swift calling static methods: type(of: self) vs explicit class name

In swift, an instance func can't call a static/class func without prefixing the method call with the class name. OR you can use type(of: self), e.g
class Foo {
static func doIt() { }
func callIt() {
Foo.doIt() // This works
type(of: self).doIt() // Or this
doIt() // This doesn't compile (unresolved identifier)
}
}
My question is, what's the difference here?
Is it just a matter of coding style, or is there some difference e.g. static or dynamic dispatch going on?
If it is just coding style, what's the preferred style?
There are two main differences.
1. The value of self inside the static method
The metatype that you call the static method on is available to you in the method as self (it's simply passed as an implicit parameter). Therefore if you call doIt() on type(of: self), self will be the dynamic metatype of the instance. If you call it on Foo, self will be Foo.self.
class Foo {
static func doIt() {
print("hey I'm of type \(self)")
}
func callDoItOnDynamicType() {
type(of: self).doIt() // call on the dynamic metatype of the instance.
}
func classDoItOnFoo() {
Foo.doIt() // call on the metatype Foo.self.
}
}
class Bar : Foo {}
let f: Foo = Bar()
f.callDoItOnDynamicType() // hey I'm of type Bar
f.classDoItOnFoo() // hey I'm of type Foo
This difference can be really important for factory methods, as it determines the type of instance you create.
class Foo {
required init() {}
static func create() -> Self {
return self.init()
}
func createDynamic() -> Foo {
return type(of: self).create()
}
func createFoo() -> Foo {
return Foo.create()
}
}
class Bar : Foo {}
let f: Foo = Bar()
print(f.createDynamic()) // Bar
print(f.createFoo()) // Foo
2. The dispatching of the static method
(Martin has already covered this, but I thought I would add it for the sake of completion.)
For class methods that are overridden in subclasses, the value of the metatype that you call the method on determines which implementation to call.
If called on a metatype that is known at compile time (e.g Foo.doIt()), Swift is able to statically dispatch the call. However, if you call the method on a metatype that isn't known until runtime (e.g type(of: self)), the method call will be dynamically dispatched to the correct implementation for the metatype value.
class Foo {
class func doIt() {
print("Foo's doIt")
}
func callDoItOnDynamicType() {
type(of: self).doIt() // the call to doIt() will be dynamically dispatched.
}
func classDoItOnFoo() {
Foo.doIt() // will be statically dispatched.
}
}
class Bar : Foo {
override class func doIt() {
print("Bar's doIt")
}
}
let f: Foo = Bar()
f.callDoItOnDynamicType() // Bar's doIt
f.classDoItOnFoo() // Foo's doIt
For a class method it makes a difference if the method is
overridden in a subclass:
class Foo {
class func doIt() {
print("Foo doit")
}
func callViaClassname() {
Foo.doIt()
}
func callViaTypeOf() {
type(of: self).doIt()
}
}
class Bar: Foo {
override class func doIt() {
print("Bar doit")
}
}
Bar().callViaClassname() // Foo doit
Bar().callViaTypeOf() // Bar doit
This is also documented in "Types" in the Swift Language Reference:
You can use a type(of:) expression with an instance of a type to access that instance’s dynamic, runtime type as a value, ...
I don't know a difference for a static method (which is final
and cannot be overridden in a subclass).
Correction: See Hamish's answer for the difference
in both static and class methods.

How do I declare a generic function in a protocol that returns self? [duplicate]

I have a protocol P that returns a copy of the object:
protocol P {
func copy() -> Self
}
and a class C that implements P:
class C : P {
func copy() -> Self {
return C()
}
}
However, whether I put the return value as Self I get the following error:
Cannot convert return expression of type 'C' to return type 'Self'
I also tried returning C.
class C : P {
func copy() -> C {
return C()
}
}
That resulted in the following error:
Method 'copy()' in non-final class 'C' must return Self to conform
to protocol 'P'
Nothing works except for the case where I prefix class C with final ie do:
final class C : P {
func copy() -> C {
return C()
}
}
However if I want to subclass C then nothing would work. Is there any way around this?
The problem is that you're making a promise that the compiler can't prove you'll keep.
So you created this promise: Calling copy() will return its own type, fully initialized.
But then you implemented copy() this way:
func copy() -> Self {
return C()
}
Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:
func copy() -> Self {
return Self()
}
Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)
OK, well how about:
func copy() -> C {
return C()
}
Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.
"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:
func copy() -> AnyObject!
So you can do the same (there's no reason for the ! here):
protocol Copyable {
func copy() -> AnyObject
}
That says "I'm not promising anything about what you get back." You could also say:
protocol Copyable {
func copy() -> Copyable
}
That's a promise you can make.
But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
And that is how you should perform copies.
We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.
With Swift 2, we can use protocol extensions for this.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
There is another way to do what you want that involves taking advantage of Swift's associated type. Here's a simple example:
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
Actually, there is a trick that allows to easily return Self when required by a protocol (gist):
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Swift 5.1 now allow a forced cast to Self, as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
Following on Rob's suggestion, this could be made more generic with associated types. I've changed the example a bit to demonstrate the benefits of the approach.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
#objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
I had a similar problem and came up with something that may be useful so I though i'd share it for future reference because this is one of the first places I found when searching for a solution.
As stated above, the problem is the ambiguity of the return type for the copy() function. This can be illustrated very clearly by separating the copy() -> C and copy() -> P functions:
So, assuming you define the protocol and class as follows:
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
This compiles and produces the expected results when the type of the return value is explicit. Any time the compiler has to decide what the return type should be (on its own), it will find the situation ambiguous and fail for all concrete classes that implement the P protocol.
For example:
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
In conclusion, this would work in situations where you're either, not using the base class's copy() function or you always have explicit type context.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()

class function with generic return value

Right now I have the following classes:
class A {
class func instantiate() -> A {
return MakeObject()
}
}
class B: A {}
let x = B.instantiate()
This results in x being of type A. How can I change instantiate in order to return an instance of the subclass that was called from? In other words, so that x ends up being of type B.
EDIT:
This is what I used to solve it, based on Martin R's answers:
class A {
class func instantiate() -> Self {
func helper<T>() -> T {
return MakeObject() as! T
}
return helper()
}
}
The returns type needs to be Self (which is the concrete type when
the class method is called), and initialization must be done with a
required init method (which can be overridden in a subclass):
class A {
class func instantiate() -> Self {
return self.init()
}
required init() {
}
}
class B: A {}
let x = B.instantiate() // `x` has type `B`
Alternatively, just define an init method
init(parameters ...) {
}
which "automatically" returns instances of the class that is is
called on.

How to use a protocol with associative type as return value in Swift?

I'm trying to use a protocol with associated type as return value of a class func.
Another post here on stackoverflow is about the same question and based on this post's answer I tried the following:
// addArg takes a single Int argument and returns something,
// which is capable of adding a another Int argument
class OpWithNoArg {
func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP {
return OpWithOneArgImpl() // (1) error here !
}
}
// a protocol with associated type, which allows adding another
// argument of a not yet specified type
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
}
// an implementation of the protocol above,
// which fixes the associated type to an Int
class OpWithOneArgImpl : OpWithOneArg {
typealias ArgType = Int
func addAnotherArg(arg: Int) {
// ...
}
}
The error in Xcode 7.0 Beta 4 on line marked with (1) is
cannot convert return expression of type 'OpWithOneArgImpl' to
expected return type 'OP'
If I change the return value to an optional and nil is returned, the sample compiles successfully:
// return null
class OpWithNoArg {
func addArg<OP: OpWithOneArg where OP.ArgType == Int>(arg: Int) -> OP? {
// return OpWithOneArgImpl()
return nil
}
}
Is this way of using a protocol with associative type as return value possible in swift, and if that's the case, how can the compiler error mentioned above be fixed?
Thanks in advance!
EDIT:
In Java, the code would be something like the following snippet. I try to find a way in Swift to achieve the same.
class C {
<T> P<T> f(T arg) {
return new PImpl();
}
}
interface P<S> {
void g(S arg);
}
class PImpl<S> implements P<S> {
PImpl() {}
public void g(S arg) {}
}
Not clear what you are trying to achieve, but imho the error stems from the fact that in your addArg function you define a generic type OP which should be typically used in the function's arguments and body.
Instead you return a non generic type trying to force it to be treated as a generic `OP.
A quick fix could be a force cast to OP of your return object:
return OpWithOneArgImpl() as !OP
but I wouldn't recommend it.
In your example your addArg will always return a OpWithOneArgImpl thus it could just be defined as a func addArg(arg: Int) -> OpWithOneArgImpl
Hope this helps.
EDIT:
Probably this is not what you're trying to achieve, but hope it can help
with a clearer explanation of what I intended above.
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}
class OpWithOneArgImpl : OpWithOneArg {
typealias ArgType = Int
func addAnotherArg(arg: Int) {
// ...
}
required init() {
// init implementation
}
}
class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg where OP.ArgType == Int>(op: OP.Type, arg: Int) -> OP {
return OP() // Here we use the init
}
}
let foo = OpWithNoArg()
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)
Edit:
Maybe you might investigate the use of generic types:
protocol OpWithOneArg {
typealias ArgType
func addAnotherArg(arg: ArgType)
init() // Must have a init with no argument
}
class OpWithOneArgImpl<T> : OpWithOneArg { // Generic implementation confirming to protocol
typealias ArgType = T
func addAnotherArg(arg: T) {
// ...
}
required init() {
// init implementation
}
}
class OpWithNoArg {
func addArgWithOPType<OP: OpWithOneArg>(op: OP.Type, arg: OP.ArgType) -> OP {
return OP() // Here we use the init
}
}
let foo = OpWithNoArg()
// OpWithOneArgImpl<Int>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: 3)
// OpWithOneArgImpl<String>
foo.addArgWithOPType(OpWithOneArgImpl.self, arg: "Hello")