Avoiding segmentation fault 11 in Xcode 7 with StringLiteralConvertible

I read a great article on StringLiteralConvertible over at NetGuru but when I tried to implement the RegularExpression, Xcode 7 (and 7.1b3) Playgrounds continually crashed.

It took a lot of experimenting (and some hints from NSHipster) but I finally got it to work.

My original (crashing) example looked like:

struct RegularExpression {
    let pattern: String
    init (pattern: String) {
        self.pattern = pattern
    }
    
}

extension RegularExpression : StringLiteralConvertible {
    init(stringLiteral value: Self.StringLiteralType) {
        self.pattern = value
    }
}

let r: RegularExpression = "hello"

but this would just crash the Playground over and over. I moved the code into an iOS app and saw a different crash and an error complaining about Self.StringLiteralType, asking if I meant RegularExpression.StringLiteralType instead.

After some digging around, I discovered that I needed to implement ExtendedGraphemeClusterLiteralConvertible and UnicodeScalarLiteralConvertible as well. On top of this, part of those protocols is declaring ExtendedGraphemeClusterLiteralType and UnicodeScalarLiteralType.

While StringLiteralType is also required to be declared, it seems that because we are directly implementing StringLiteralConvertible, we don’t need to declare it. This is what appears to be the bug, that Swift is not picking up default types for ExtendedGraphemeClusterLiteralType and UnicodeScalarLiteralType.

With this info, I was able to get the code to compile and work (for String, I did not try graphemes nor unicode) as such:

struct RegularExpression {
    let pattern: String
    init (pattern: String) {
        self.pattern = pattern
    }
    
}

extension RegularExpression : StringLiteralConvertible {
    typealias ExtendedGraphemeClusterLiteralType = StringLiteralType
    typealias UnicodeScalarLiteralType = UnicodeScalar

    init(extendedGraphemeClusterLiteral value: ExtendedGraphemeClusterLiteralType) {
        self.pattern = value
    }
    
    init(unicodeScalarLiteral value: UnicodeScalarLiteralType) {
        self.pattern = "\(value)"
    }

    init(stringLiteral value: StringLiteralType) {
        self.pattern = value
    }
}

let r: RegularExpression = "hello"

Not I am not using Self. to reference the types, unlike the way Xcode autocompletes them.

Is this correct?

Update:

Going further in the example, I added StringInterpolationConvertible:

extension String {
    init(stringInterpolationSegment regex: RegularExpression) {
        self = regex.pattern
    }
}

let r: RegularExpression = "hello" // RegularExpression

"\(r)" // "hello"

This is a great find in the article, because StringInterpolationConvertible isn’t obvious.