Convenience initializer doesn't exist when linking

I thought it would be interesting to write a cross-platform game that uses swift instead of Unity, developing a 2D engine that mimics a subset of SpriteKit's API, but implemented in SDL for the Linux/Windows versions. I'm more familiar with Linux development, but have a Mac as well, so I'm a Swift newbie. I've encountered a strange error, which seems like a bug in the toolchain, but could be some weird quirk in Swift that I don't understand.

I wrote my own version of SKTileMapNode which has these initializers:

    public convenience init(tileSet: SKTileSet, columns: Int, rows: Int, tileSize: CGSize)
    {
        self.init(tileSet: tileSet, columns: columns, rows: rows, tileSize: tileSize)
    }

    public convenience init(tileSet: SKTileSet, columns: Int, rows: Int,
                            tileSize: CGSize, fillWith: SKTileGroup)
    {
        self.init(tileSet: tileSet, columns: columns, rows: rows,
                  tileSize: tileSize, optionalFillWith: fillWith)
    }

    private init(tileSet: SKTileSet, columns: Int, rows: Int, tileSize: CGSize,
                 optionalFillWith fillWith: SKTileGroup?) { ... }

Then I derived a subclass from it with this initializer:

init(tileSize: Int, viewSize: CGSize) {
    ...
    super.init(tileSet: ..., columns: ..., rows: ..., tileSize: CGSize(width: ..., height: ...))
    ...
}

This subclass worked on the Mac with the "real" SKTileMapNode, and sourcekit-lsp also thinks it's OK on Linux, but when I try to build the project on Linux, I get this error:

error: undefined reference to '$s7Repton213SKTileMapNodeC7tileSet7columns4rows0E4SizeAcA0bF0C_S2i10Foundation6CGSizeVtcfc'

The line number refers to the line where I call super.init(...) in the custom subclass. I've fixed the problem by removing the convenience initializers from SKTileMapNode and changing the private one to:

public init(tileSet: SKTileSet, columns: Int, rows: Int,
                            tileSize: CGSize, fillWith: SKTileGroup? = nil)

But I'm curious, why didn't it work with the convenience initializer(s)? FWIW I'm using swift-bin 5.4-1 from the Arch Linux AUR.

This is extremely subtle, but your first convenience init calls itself instead of the underlying designated init. I wonder if the Linux compiler said “oh, well, calling this is impossible because it’ll send the program into an infinite loop, so I might as well delete it”. I think I would consider that a bug, if it does turn out to be the cause; the compiler could replace the method with a trap, but shouldn’t delete it altogether.

Thanks. I think you flatter me by calling it extremely subtle, I should have spotted the ambiguous signatures.

Terms of Service

Privacy Policy

Cookie Policy