[swift-evolution] URL Literals

David Sweeris davesweeris at mac.com
Mon Dec 19 01:41:00 CST 2016


> On Dec 17, 2016, at 1:12 PM, Micah Hainline via swift-evolution <swift-evolution at swift.org> wrote:
> 
> I'd love a fleshed out elegant example for URL that shows what a complete implementation of that special init method would look like. 

Sorry this took so long… the weekend kinda got away from me.

Anyway, I was thinking something like this (which has been very simplified on account of my regexing being sub-sketchy, and me not knowing exactly what’s valid in an URL anyway):
#literalpatterns += (name: “URLLiteralType”, components: (name: url, type: StringLiteralType, pattern: “(http|https)://(www.)?[a-z|A-Z|0-9]+.(com|org|net)(/[a-z|A-Z|0-9]+)*(/[a-z|A-Z|0-9]+.[a-z|A-Z|0-9]+)?”), protocol: ExpressibleByURLLiteral)
This would let the compiler know pretty much everything it needs to know… that the “new” type is called “URLLiteralType", that it starts out life as young StringLiteralType with a bright future in the computer industry, that in order to succeed it has to match a given pattern, and what protocol a type has to conform to in order to use an URLLiteral. In practice, the compiler would synthesize a struct containing the specified members and validate the literal with the specified pattern before making an “instance” of it (since we’re talking about literals and compile-time code here, I’m pretty sure that “instance" the wrong terminology… pardon my ignorance)
struct URLLiteralType: {
    let url: StringLiteralType
}
A tuple would be better, IMHO, but according to the playground, single-element tuples can’t have element labels. As for the implementation of the init function:
init(urlLiteral value: URLLiteralType) {
    let urlString = value.url
    //Do whatever URL is doing now, except there’s no need to check for errors since the compiler pre-validated it for us
}

If it’d be more useful, the pattern could be split into multiple pieces:
#literalpatterns += (name: “URLLiteralType”,
                     components: ((name: “`protocol`", type: StringLiteralType, pattern: “(http|https)”),
                                  (name: _,            type: StringLiteralType, pattern: “://”),
                                  (name: “domain",     type: StringLiteralType, pattern: “(www.)?[a-z|A-Z|0-9]+.(com|org|net)”),
                                  (name: “path”,       type: StringLiteralType, pattern: "(/[a-z|A-Z|0-9]+)*(/[a-z|A-Z|0-9]+.[a-z|A-Z|0-9]+)?”))
                     protocol: ExpressibleByURLLiteral)
This would result in URLLiteralType looking like this:
struct URLLiteralType: {
    let `protocol`: StringLiteralType
    let domain: StringLiteralType
    let path: StringLiteralType
}
And in the init would start out like this:
init(urlLiteral value: URLLiteralType) {
    let protocolType = value.protocol
    let domain = value.domain
    let path = value.path
    //Do whatever with the components
}

The “base” types of literals like Int or String that don’t refine pre-existing literal types would still need a bit of compiler magic (or at least a different mechanism for becoming actual types), but as long as a type doesn’t take advantage of reference semantics in its stored properties or something, I *think* pretty much any data type could become “literalizeable” with something like this. Oh, and there’s nothing particularly magical about regular expressions as far as this idea is concerned; they’re just usually the first thing that comes to mind when I think of pattern matching in a string. 

I know this looks like a lot of code, but the scary-looking parts with the regex stuff only has to be written once for each “type” of literal… types that want to be expressible by such a literal just have to write an init function.





While I was writing this up, it occurred to me that another solution would be to have a set of "ExpressibleByValidated*Literal” protocols, where the init is failable and has to be @pure/@constexpr/@whateverthecompilerneedstorunitatcompiletime. That way the literal can be validated simply by calling the init and checking if it returns nil. Make `URL` conform to `ExpressibleByValidatedStringLiteral`, and you'll get the complie-time validation functionality just by copying whatever’s in the current `URL.init?(string: String)` function.

- Dave Sweeris
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161218/2c6dd147/attachment.html>


More information about the swift-evolution mailing list