Question background
I have a question based on my own attempt to yield a satisfactory workaround for the behaviour wanted by the OP of the following thread:
The subject is (like a few others here at SO...) attempting to mimic generic array extensions that conform to some protocol. There was a recent similar question regarding this subject in this thread:
Question
My question cover the next step. Lets say we manage to implement a somewhat generic extension to Array, conforming to some protocol blueprints, say MyProtocol. Hence, from now on, assume that Array instances, for some types of Generator.Element (say, for MyTypes), are now extended and conforms to MyProtocol.
Then, for a function taking a generic Array (or, specifically, say <U: _ArrayType ..., or possibly RangeReplaceableCollectionType ... or SequenceType ...) type) as argument, is there any way to add a type constraint to the actual generic array (U), and not just to its Generator.Element type? (so not ... where Generator.Element.Type == SomeTypeConstraint).
Example
I'll try to show my question "in action" to help specify what I'm actually asking. Note that this is the most MWE I've been able to construct for this purpose, my apologies if it's possibly a bit hefty.
Protocols (protocol MyTypes for use as type + protocol MyProtocol used for array extension):
/* Used as type constraint for Generator.Element */
protocol MyTypes {
var intValue: Int { get }
init(_ value: Int)
func *(lhs: Self, rhs: Self) -> Self
func +=(inout lhs: Self, rhs: Self)
}
extension Int : MyTypes { var intValue: Int { return self } }
extension Double : MyTypes { var intValue: Int { return Int(self) } }
/* Let's not extend 'Float' for now
extension Float : MyTypes { var intValue: Int { return Int(self) } } */
/* Used as extension to Array : blueprints for extension method
to Array where Generator.Element: are constrainted to MyTypes */
protocol MyProtocol {
//typealias T
func foo<T: MyTypes>(a: [T]) -> Int?
}
Extension of Array by MyProtocol; implementation of blue-printed method:
extension Array : MyProtocol {
func foo<T: MyTypes>(a: [T]) -> Int? {
/* [T] is Self? proceed, otherwise return nil */
if let b = self.first {
if b is T && self.count == a.count {
var myMultSum: T = T(0)
for (i, sElem) in self.enumerate() {
myMultSum += (sElem as! T) * a[i]
}
return myMultSum.intValue
}
}
return nil
}
}
Some tests where we, for a function, constrain the Generator.Element of the Array arguments to MyTypes, hence somewhat implicitly asserting that only arrays conforming to MyProtocol can use the function:
/* Tests */
let arr1d : [Double] = [1.0, 2.0, 3.0]
let arr2d : [Double] = [-3.0, -2.0, 1.0]
let arr1f : [Float] = [1.0, 2.0, 3.0]
let arr2f : [Float] = [-3.0, -2.0, 1.0]
func bar1<U: MyTypes> (arr1: [U], _ arr2: [U]) -> Int? {
return arr1.foo(arr2)
}
let myInt1d = bar1(arr1d, arr2d) // -4, OK
//let myInt1f = bar1(arr1f, arr2f)
/* Error: Cannot convert value of type '[Float]'
to expected argument type '[_]'
OK! Expected as 'Float' does not conform to MyTypes protocol */
We've now arrived to the core of my question, something I haven't been able to construct myself: Is there any possible way to explicitly constrain an array generic, say U, to MyProtocol (for which Array for some Generator.Elements have been constrained)? I would like to do something along the lines
func bar2<T: MyTypes, U: protocol<MyProtocol, _ArrayType> where U.Generator.Element == T> (arr1: U, _ arr2: U) -> Int? {
// OK, type 'U' behaves as an array type with elements 'T' (==MyTypes)
var a = arr1
var b = arr2
a.append(T(0))
b.append(T(0))
return a.foo(b)
/* Error: Cannot convert value of type 'U'
to expected argument type '[_]' */
}
let myInt2 = bar2(arr1d, arr2d)
- Is this possible, perhaps in a different manner?
(Feel free to edit this question to improve it, I'm not very well versed at the process of asking, and the best practice for, questions here at SO)