Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

swift

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?

like image 353
marcprux Avatar asked Jul 21 '14 19:07

marcprux


1 Answers

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())
    }
}
like image 80
matt Avatar answered Nov 15 '22 08:11

matt