Swift 2.0 enables you to add public extensions of generic types. In Beta 2, extensions can be constrained by adding protocol requirements on the type parameters of the generic type.
Last night, Gal3rielol asked if he could use extensions to add methods to arrays with restricted types, such as [Int] or [MyType].
You cannot add specific typing, like
extension Array where Element == Int
because this type requirement transforms the generic Array into a non-generic version.
Nor, can you perform an extension on Array<Int>:
error: constrained extension must be declared on the unspecialized generic type 'Array' with constraints specified by a 'where' clause
You can find or create a protocol that limits your extension to more or less just the type you want to work with:
extension Array where T : StringLiteralConvertible extension Array where T : IntegerArithmeticType
Or create a custom protocol and use it restrict the items your extension works with:
protocol OnlyStrings {} extension String: OnlyStrings{} extension Array where T : OnlyStrings
This approach is limited. While you know the extension only applies to strings, the compiler is still working with type T. This example by Mike Ash demonstrates the issue:
extension Array where T : OnlyStrings { func appendAll() -> String { var accumulator = "" for item in self { accumulator += item } return accumulator } }
This errors with “error: binary operator ‘+=’ cannot be applied to operands of type ‘String’ and ‘T’” Work around this by casting item to String(item). You should also add a StringLiteralConvertible restriction. It’s inelegant at best.
3 Comments
> This errors with “error: binary operator ‘+=’ cannot be applied to operands of type ‘String’ and ‘T’”
if let item = item as? T
I’m thinking that being able to write T == String (or T: String) and so on will follow in later betas. After all we can already use classes and write things like T: UIView, so why not? But for now how about this as a way to reduce an array of strings into a single string (using an extension):
—————–
protocol StringType {
var characters: String.CharacterView { get }
}
extension String:StringType {
}
extension Array where T:StringType {
func appendAll() -> String {
return String(self.map{$0.characters}.reduce(String.CharacterView(), combine: {$0 + $1}))
}
}
[“Hello “,”Swift”,”!”].appendAll() // Hello Swift!
——————–
Please forgive the indulgence of responding to my own comment, but it’s worth noting for those who are actually looking to reduce an array of strings into a single string, that this particular example is really an academic exercise because IRL we’d just use one of the pre-existing methods:
——-
“”.join([“one”,”two”,”three”]) // “onetwothree”
[“one”,”two”,”three”].reduce(“”,combine:{$0 + $1}) // “onetwothree”
——-