Constraining associatedtype of non-generic typealias

We don't have "constraint aliases" in the language today (it's "really not supported" AFAIK) - but I'll let you in on a little secret I discovered. This is really ugly, but believe it or not, it works:

typealias IsFloatColl<T> = T where T: Collection, T.Element: Strideable, T.Element.Stride: BinaryFloatingPoint

extension Collection where IsFloatColl<Element>: Any {
    func doSomething() {
        // type-checking works.
        self.first?.first?.advanced(by: .pi)
    }
}

func genericFunc_1D<T>(_ t: T) where IsFloatColl<T>: Any {
  t.first?.advanced(by: .pi)
}

func test() {
    let flt2D: [[Float]] = []
    let dbl2D: [[Double]]  = []
    let int2D: [[Int]] = []
    flt2D.doSomething() // Works.
    dbl2D.doSomething() // Works.
    genericFunc_1D(flt2D[0]) // Works.
    genericFunc_1D(dbl2D[0]) // Works.
    
    // int2D.doSomething()
    // Referencing instance method 'doSomething()' on 'Collection' requires that 'Int.Stride' (aka 'Int') conform to 'BinaryFloatingPoint'
    
    // genericFunc_1D(int2D[0])
    // Global function 'genericFunc_1D' requires that 'Int.Stride' (aka 'Int') conform to 'BinaryFloatingPoint'
}

It's surprisingly complete - constrained extensions and generics work, and even diagnostics see through the hack and provide good error messages. It can be a big help if you need to repeat long strings of constraints.

9 Likes