0
votes

I have read up on the Extensions available in Swift and was wondering if static protocol extensions are supported? I know that instance methods can be used in a protocol extension.

I was wanting to create a protocol for my repository, along with an implementation of that repository:

Repository protocol

public protocol NoteRepositoryProtocol {
    func getAllNotes() -> [Note]
}

Repository implementation

class NoteRepository : NoteRepositoryProtocol {
    func getAllNotes() -> [Note] {
        return [Note]()
    }
}

Then in order to maintain loose coupling within my application, I wanted to create the repository through a factory. I was trying to be clever and attach a static method to my protocols like so:

public extension NoteRepositoryProtocol {
    public static func createInstance() -> NoteRepositoryProtocol {
        return NoteRepository()
    }
}

I know this can be done if I drop the static keyword here, but i really wanted it to be static so I could do this:

func test_note_repository_returns_a_valid_note_repository() {
    let repository = NoteRepositoryProtocol.createInstance()
}

Now when I want to change my repository implementation out, I could do so by updating my protocol extension factory method. The other alternative is to create an actual factory to handle this, but I like the idea of a factory method existing on the type itself.

When I compile this, I am given the following complier error:

Command failed due to signal: Illegal instruction: 4

warning: initialization of immutable value 'repository' was never used; consider replacing with assignment to '_' or removing it let repository = NoteRepositoryProtocol.createInstance() ~~~~^~~~~~~~~~ _ not existential UNREACHABLE executed at /Library/Caches/com.apple.xbs/Sources/swiftlang/swiftlang-700.0.38.1/src/swift/lib/SILGen/SILGenExpr.cpp:3311! 0 swift 0x0000000106760e0b llvm::sys::PrintStackTrace(__sFILE*) + 43 1 swift 0x000000010676154b SignalHandler(int) + 379 2 libsystem_platform.dylib 0x00007fff9440ef1a _sigtramp + 26 3 swift 0x0000000106d5aa2e FirstTarget + 60550 4 swift 0x0000000106761346 abort + 22 5 swift 0x000000010671ae21 llvm::llvm_unreachable_internal(char const*, char const*, unsigned int) + 481 6 swift 0x00000001049b503c swift::Lowering::SILGenFunction::emitOpenExistentialImpl(swift::OpenExistentialExpr*, llvm::function_ref) + 2588 7 swift 0x00000001049c0ba1 swift::Lowering::RValue swift::Lowering::SILGenFunction::emitOpenExistential(swift::OpenExistentialExpr*, (anonymous namespace)::RValueEmitter::visitOpenExistentialExpr(swift::OpenExistentialExpr*, swift::Lowering::SGFContext)::$_0) + 65 8 swift 0x00000001049b6f00 swift::ASTVisitor<(anonymous namespace)::RValueEmitter, swift::Lowering::RValue, void, void, void, void, void, swift::Lowering::SGFContext>::visit(swift::Expr*, swift::Lowering::SGFContext) + 4864 9 swift 0x00000001049af49f swift::Lowering::SILGenFunction::emitExprInto(swift::Expr*, swift::Lowering::Initialization*) + 303 10 swift 0x00000001049a0dd8 swift::Lowering::SILGenFunction::visitPatternBindingDecl(swift::PatternBindingDecl*) + 232 11 swift 0x0000000104a021fa swift::ASTVisitor<(anonymous namespace)::StmtEmitter, void, void, void, void, void, void>::visit(swift::Stmt*) + 362 12 swift 0x0000000104a02085 swift::Lowering::SILGenFunction::emitStmt(swift::Stmt*) + 21 13 swift 0x00000001049ca136 swift::Lowering::SILGenFunction::emitFunction(swift::FuncDecl*) + 390 14 swift 0x000000010496d3ed swift::Lowering::SILGenModule::emitFunction(swift::FuncDecl*) + 253 15 swift 0x0000000104a0833c (anonymous namespace)::SILGenType::emitType() + 956 16 swift 0x0000000104a07ede swift::Lowering::SILGenModule::visitNominalTypeDecl(swift::NominalTypeDecl*) + 30 17 swift 0x000000010497028b swift::Lowering::SILGenModule::emitSourceFile(swift::SourceFile*, unsigned int) + 571 18 swift 0x000000010497106f swift::SILModule::constructSIL(swift::ModuleDecl*, swift::SILOptions&, swift::FileUnit*, llvm::Optional, bool, bool) + 703 19 swift 0x000000010497128b swift::performSILGeneration(swift::FileUnit&, swift::SILOptions&, llvm::Optional, bool) + 123 20 swift 0x000000010477a691 performCompile(swift::CompilerInstance&, swift::CompilerInvocation&, llvm::ArrayRef, int&) + 9153 21 swift 0x00000001047780b3 frontend_main(llvm::ArrayRef, char const*, void*) + 2515 22 swift 0x000000010477428f main + 1983 23 libdyld.dylib 0x00007fff934fb5c9 start + 1 24 libdyld.dylib 0x0000000000000048 start + 1823492736

Can you not use static methods in a protocol extension?

Update

I removed the unit test assertion to improve the root of the problem in the example source. The issue is that the compiler doesn't like my invoking the static method on the protocol.

2
To me this looks like a bug.Sebastian Dressler
I'll take a look at creating a bug on it.Johnathon Sullinger

2 Answers

1
votes

a non optional never can be nil

public static func createInstance() -> NoteRepositoryProtocol? {
    return NoteRepository()
}
0
votes

As explained in the Apple Documentation:

Protocols do not actually implement any functionality themselves. Nonetheless, any protocol you create will become a fully-fledged type for use in your code.

Hence, you can not directly call static methods of a protocol.