J. Cocoe J. Cocoe - 4 months ago 17
Swift Question

Swift extension for [String]?

I'm trying to write an extension method for

[String]
.

It seems you can't extend
[String]
directly ("Type 'Element' constrained to non-protocol type 'String'"), though I came across this trick:

protocol StringType { }
extension String: StringType { }


But I still can't quite make the Swift type system happy with this:

extension Array where Element: StringType {
// ["a","b","c","d","e"] -> "a, b, c, d, or e".
func joinWithCommas() -> String {
switch count {
case 0, 1, 2:
return joinWithSeparator(" or ")
default:
return dropLast(1).joinWithSeparator(", ") + ", or " + last!
}
}
}


The
joinWithSeparator
calls are "Ambiguous". I've tried everything I could think of, like using
(self as! [String])
(and a bunch of similar variants), but nothing seems to work.

How can I make the Swift compiler happy with this?

Answer

You could follow the declaration of joinWithSeparator (Cmd-click on it) and find that it is defined as an extension of the protocol SequenceType instead of the type Array.

extension SequenceType where Generator.Element == String {
    public func joinWithSeparator(separator: String) -> String
}

We could do the same with your function, where we extend a protocol adopted by Array instead of Array itself:

extension CollectionType where
        Generator.Element == String,
        SubSequence.Generator.Element == String,
        Index: BidirectionalIndexType
{
    func joinWithCommas() -> String {
        switch count {
        case 0, 1, 2:
            return joinWithSeparator(" or ")
        default:
            return dropLast(1).joinWithSeparator(", ") + ", or " + last!
        }
    }
}

Note:

  • we extend CollectionType to be able to use count
  • we constraint Generator.Element == String to use joinWithSeparator
  • we constraint SubSequence.Generator.Element == String to ensure dropLast(1) can use joinWithSeparator. dropLast(1) returns the associated type SubSequence.
  • we constraint Index: BidirectionalIndexType to use last.
Comments