Search code examples
swiftgenericsprotocolsgenetic-algorithm

Swift, Protocols and Generics in Genetic Algorithm


I am trying to switch from Java to Swift and improve my programming skills in this language.

However, I have some difficulties understanding how generics works in Swift after a study of:

https://docs.swift.org/swift-book/LanguageGuide/Generics.html

I have started to write a genetic algorithm by writing some protocols.

protocol Point : Equatable {
    var identifier: String { get }
    var x: Double { get }
    var y: Double { get }
    func distance<P : Point>(to point: P) -> Double
}

protocol Individual {
    associatedtype P : Point
    var fitness: Double { get }
    var chromosomes: [P] { get }
}

and now I want to make a struct which conforms to the Individual protocol.

The only try that compiles is

struct Route : Individual {
    typealias P = City;
    var fitness: Double { 0.0 }
    var chromosomes: [City]
}

However, I want to make Route as much as generic, therefore I don't want to tell that it uses City as implementation of Point. I want that Route knows that it works on array of objects which conforms to Point protocol.

I'd appreciate your help.

Thank you in advance.


Solution

  • First of all, I'd suggest adding a Self requirement on the distance(to:) method. Self just tells the compiler that the paremeter is the same type as the conforming type.

    protocol Point : Equatable {
        var identifier: String { get }
        var x: Double { get }
        var y: Double { get }
        func distance(to point: Self) -> Double
    }
    

    So, in your City struct point must also be of type City.

    struct City: Point {
        var identifier: String
        var x: Double
        var y: Double
    
        func distance(to point: City) -> Double {
            return .zero
        }
    }
    

    You can make your Route struct more flexible by adding a generic parameter that also satisfies the associated type requirement imposed by the Individual protocol.

    struct Route<P: Point>: Individual {
        var fitness: Double { 0.0 }
        var chromosomes: [P]
    }
    

    To instantiate a Route:

    var cityRoute = Route<City>(chromosomes: [])