Covariant 'Self' or 'Self?' error when static func → [Self]

Hello guys,
I might need your advice / help on this example.

I have SQL tables and want to have Objects from these tables.
In every tables I have an id column so I based my code as followed


public class TableObject {
    var id: Int?
    
    var table: Table { Database.EmptyTable() }
    
    class var table: Table { Database.EmptyTable() }
    
    required init(from: [String: Any]) throws {
        guard let id = from["id"] as? Int else {
            throw TableObjectError.initializationFailed
        }
        self.id = id
    }
    
    init() {
        self.id = nil
    }
    
    public static func selectAll() throws -> [Self] {
        ...
    }
    
    public static func select(_ id: Int) throws -> Self? {
        ...
    }
}

The TableObject is like an abstract Class that I subclass with my concrete class reflecting my tables in database.

This works properly and gives me proper object type when I call it

public static func select(_ id: Int) throws -> Self?

But this gives me this error: "Covariant 'Self' or 'Self?' can only appear at the top level of method result type"

public static func selectAll() throws -> [Self]

I can use

public static func selectAll() throws → [Any]

and type cast every time I need, but it's less convenient...

Am I doing something wrong ?

Thanks in advance for your help :slight_smile:

Inheritance is generally not a great choice, for any problem, in any programming language, even if it is the best choice available. In Swift, the best choice available is turning TableObject into a protocol. You'll need to copy boilerplate in the form of instance members and initializers—you can macro that up if you want.

2 Likes

This post by @Slava_Pestov might answer your question.

2 Likes

Arrays are special because they have a covariant conversion, so it would actually be sound to allow this case. We already allow returning Self?, and you can imagine generalizing this so that you can even return a type like (Self, [Self], Self.Type, () -> Self) if you want.

The implicitly opened existential feature also supports more complex cases like this, but the “dynamic Self in class” is a separate concept that predates a lot of other things in the implementation.

4 Likes

I was using protocols and extensions but because I'm building a library, I want to have var id: Int? and static var table: Table to be internal and not presented as public.
But since my public static getAll() throws → [Self] is public and using table, I have conflicts on access levels... :(
I will look at it if I can find a way for this but everything I tried, I get conflicts

1 Like

I agree, and I'm using it on public static func select(_ id: Int) throws → Self?, and this is working properly

But when I write public static func getAll() throws → [Self], I get this covariant error.

public static func getAll() throws → [Self]  { //Covariant error is just here
    let elements = ... //Select all from database
    var result: [Self] = [] //No errors here
    for element in elements {
        result.append(... /*init self from element*/)
    }
    return result //Get no error from here
}

I was expecting to have an error when creating var result: [Self] but no. This is why I'm wondering why I can create the [Self] in the method but not able or returning it...

1 Like

The rules around the appearance of Self in a class method signature are stricter than those for local declarations inside the method, because of subclassing and method overriding.

2 Likes

Ok Thanks for help :slight_smile: !

While I would still use underscore-prefixed protocol requirements for what you're talking about, true satisfaction of requirements by private members is definitely a missing feature. I think this might be the most involved relevant discussion: Pitch: Protocols with private fields .

2 Likes