Extending a concrete type where Self has retroactive conformance

i have a protocol HTTP.ServerLoop that has some requirements and provides a method runServer()

public protocol ServerLoop
{
    func allow(origin:IP) -> Bool
    func x()
    func y()
}
extension HTTP.ServerLoop
{
    func runServer()
}

there is an actor SharedServer that provides all the witnesses except for allow(origin:), and lives in a module called CoreServer. the idea is that a downstream module will extend SharedServer with the necessary allow(origin:) requirement and declare the ServerLoop conformance.

there are two such modules, a public module with a stub implementation, and a private module that provides a proprietary implementation.

public module:

import CoreServer 

extension SharedServer:HTTP.ServerLoop
{
    public
    func allow(origin:IP) -> Bool
    {
        //  Allow everything.
        return true
    }
}

proprietary module:

import CoreServer 

extension SharedServer:HTTP.ServerLoop
{
    public
    func allow(origin:IP) -> Bool
    {
        //  Enforce firewall rules
        ...
    }
}

now, i would like to write some extension in the CoreServer module that assumes a conformance that does not yet exist at this level.

extension SharedServer where Self:HTTP.ServerLoop
{
    public
    func run() async throws
    {
        //  calls `runServer()`
    }
}

but it seems this is not allowed.

trailing 'where' clause for extension of non-generic type 'Unidoc.ServerLoop'

this run() method accesses a lot of private implementation details of SharedServer. so it is not a good candidate for refactoring into some SharedServerProtocol. are there any other ways to assume a conformance that is expected to be declared in a client module?

You can flip the requirements:

extension HTTP.ServerLoop where Self: SharedServer {}

I recently run into this as well. I wish both spelling would be accepted.

3 Likes

ah, it has to be spelled with a colon! i had tried writing this

extension HTTP.ServerLoop where Self == TheServerLoop

and encountered the no type for 'Self' can satisfy both 'Self == TheServerLoop' and 'Self : HTTP.ServerLoop' error so i assumed this was not allowed.

it’s not quite the same, as the protocol extension cannot access any private members, but that is acceptable to me.

(the error perplexes me, TheServerLoop is an actor which cannot possibly have subclasses. so i do not understand why there is a difference between : and ==.)

1 Like