Self' Is Only Available in a Protocol or as the Result of a Class Method

Self' is only available in a protocol or as the result of a class method

The problem, I suspect, is that Self is ambiguous; it means "this class or a subclass, whatever the thing happens to be at the time we are called". In other words, Self is polymorphic. But you can't make an array consisting of two different classes, for example. And although the class may permit a certain initializer, we cannot know in advance that its subclass will.

The solution is to use the class name itself. Here's an example for a struct Thing:

extension Thing {
static func makeTwo() -> (Thing, Thing) {
return (Thing(), Thing())
}
}

How to use Self for method return types in Swift?

With such a hierarchy, you would have to make the class conforming to the protocol final:

protocol Marker {
func copy() -> Self
}
final class Marker1 : Marker {
func copy() -> Marker1 {
return Marker1()
}
}

The final is needed because when you don't apply final and you create a subclass Marker2: Marker1 then copy would not return the correct class Self any more.

You can workaround that by creating a required initializer and always create the correct instance:

protocol Marker {
init()
func copy() -> Self
}
class Marker1 : Marker {
required init() {
}
func copy() -> Self {
let copy = type(of: self).init()
return copy
}
}

(original code removed because does not work)

Related: Implementing copy() in Swift

Why using Self as return type is not considered as the protocol's constraint?

Because it's not useful to have a Self as a parameter type of a method. Suppose that you can do:

protocol P {
func f(_ x: Self)
}

class A: P {
func f(_ x: Self) {
// not relevant
}
}

class B: A { }

Now suppose I have:

func g(x: A) {
// what can I do with x?
}

The fact is, there is no way to call x.f. Because I can pass an instance of B to x, in which case x.f would accept a B instead. x could be an instance of any subclass of A that I have no way of knowing at compile time, so I don't know what I can pass to x.f.


Compare that to Self used as the return type:

protocol P {
func f() -> Self
}

// Implementation:
class A: P {
func f() -> Self {
self
}
}

class B: A { }

func g(x: A) {
let foo: A = x.f()
}

Here, we know that I can at least assign the return value of x.f to a variable of type A. Even if x is an instance of B, which means that f returns a B, we can still assign that to a variable of type A.

Swift, Self from AnyObject

You can simply return User? from your class function, if this is an option:

public class func returnFirstSelf() -> User? {
if let found = findByID("1") as? User {
return found
}
return nil
}

There's currently no way (I'm aware of) to return Self? with Swift as it stands. The problem is that Self has a somewhat... "dynamic" meaning, separate from concrete types, protocols, and even generics. A particular example that demonstrates this is: What if you have a class StudentUser that extends User? If you tried to implement it like this:

class func returnFirstSelf() -> Self? {
if let found = findById("1") as? Self { // Note the check that 'found' is a 'Self'
return found
}
return nil
}

Then you encounter a compiler error because you cannot use Self outside the result of a protocol or class method. And if you try to implement it like this:

class func returnFirstSelf() -> Self? {
if let found = findById("1") as? User { // Note 'User' instead of 'Self'
return found
}
return nil
}

Then you run the risk of Self actually meaning StudentUser, and even if you pass the check that requires found to be a User, it doesn't guarantee that found will be a StudentUser. This will occur in the case that StudentUser does not override the method to ensure that the as? checks against StudentUser.

The critical flaw here in my opinion is that you cannot use the required keyword on class methods, requiring subclasses to override them. This would allow the compiler to ensure that any subclasses have overridden the method and provided an implementation that can guarantee type safety.

Method in non-final class must return `Self` to conform to protocol

In Swift 3 or 4:

import Foundation

protocol P {
static func f() -> Self
static func g() -> Self
}

extension P {
static func f() -> Self {
return g()
}
}

extension Data: P {
static func g() -> Data {
return self.init()
}
}

Or you can replace your class with a final subclass:

import Foundation

protocol P {
static func f() -> Self
static func g() -> Self
}

extension P {
static func f() -> Self {
return g()
}
}

import Foundation

final class MyData: NSData {}
extension MyData: P {
static func g() -> Self {
return self.init()
}
}

If NSData is one of those class clusters that can't easily be subclassed (you'll see a stacktrace with __CFRequireConcreteImplementation), you may have to create a final class wrapper for a real NSData instead of using a subclass.



Related Topics



Leave a reply



Submit