mprudhom mprudhom - 4 months ago 14
Swift Question

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

Update: Swift 3 permits

Self
to be used from other types, thanks to SE-0068 – Expanding Swift Self to class members and value types.

You can return "Self" from a class function:

extension NSObject {
class func makeOne() -> Self {
return self()
}
}


So you can do:

let set : NSCountedSet = NSCountedSet.makeOne()


However, the following two don't compile:

extension NSObject {
class func makeTwo() -> (Self, Self) {
return (self(), self())
}

class func makeMany() -> [Self] {
return [self(), self(), self(), self(), self()]
}
}


The error is:

<REPL>:11:34: error: 'Self' is only available in a protocol or as the result of a class method; did you mean 'NSObject'?
class func makeTwo() -> (Self, Self) {
^~~~
NSObject
<REPL>:11:40: error: 'Self' is only available in a protocol or as the result of a class method; did you mean 'NSObject'?
class func makeTwo() -> (Self, Self) {
^~~~
NSObject
<REPL>:15:35: error: 'Self' is only available in a protocol or as the result of a class method; did you mean 'NSObject'?
class func makeMany() -> [Self] {
^~~~
NSObject


Does anyone know of any way to declare that a class function returns multiple instances of the class itself?

Answer

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())
    }
}