Search code examples
swiftgenericsprotocols

Generics in protocols


I have a UnitDimension class given by:

class UnitDimension: {
    var symbol: String
    init(symbol: String) {
        self.symbol = symbol
    }
}

and a UnitVolume subclass of this class:

class UnitVolume: UnitDimension {
    static let liter = UnitVolume(symbol: "L")
}

I want to have a protocol UnitDimensionHandler that allows me to perform some simple functions. Firstly it must have an allUnits variable:

protocol UnitDimensionHandler: class {
    static var allUnits: [UnitDimension] { get }
}

Is it possible to have allUnits a generic type of array that must be a subclass of UnitDimension? I could then implement it in UnitVolume as follows:

extension UnitVolume: UnitDimensionHandler {
    static var allUnits: [UnitVolume] {
        return [liter]
    }
}

I then want to include a function that also allows me to use a generic subclass type that initiates a UnitDimension instance:

extension UnitDimensionHandler {
    static func unit(for symbol: String) -> UnitDimension? {
        return allUnits.first() { $0.symbol == symbol }
    }
}

such that UnitVolume.unit(for: "L") returns an optional UnitVolume rather than an optional UnitDimension.

Thanks for any help.


Solution

  • Yes it is possible, using associatedtype:

    protocol UnitDimensionHandler: class {
        // here we define `generic` type variable `Dimension`, and specify it do be descendant of `UnitDimension`
        associatedtype Dimension: UnitDimension
    
        // and use it here, instead of `UnitDimension`
        static var allUnits: [Dimension] { get }
    }
    

    And

    extension UnitDimensionHandler {
        // same `UnitDimension` -> `Dimension` replacement
        static func unit(for symbol: String) -> Dimension? {
            return allUnits.first() { $0.symbol == symbol }
        }
    }