The review of URI Templating begins now and runs through March 21, 2025.
Reviews are an important part of the Swift-Foundation evolution process. All review feedback should be either on this forum thread or, if you would like to keep your feedback private, directly to me as the review manager by email or DM. When contacting the review manager directly, please include proposal name in the subject line.
What goes into a review?
The goal of the review process is to improve the proposal under review
through constructive criticism and, eventually, determine the direction of
Swift-Foundation. When writing your review, here are some questions you might want to
answer in your review:
What is your evaluation of the proposal?
Does this proposal fit well with the feel and direction of Swift-Foundation?
If you have used other languages or libraries with a similar
feature, how do you feel that this proposal compares to those?
How much effort did you put into your review? A glance, a quick
reading, or an in-depth study?
More information about Swift-Foundation review process is available here.
The URL.init?(template:variables:) initializer looks misplaced to me. I think this operation would be more naturally expressed as something like a render method on URI.Template.
Proposed (using ! for brevity):
let template = URL.Template("http://www.example.com/foo{?query,number}")!
let url = URL(template: template, variables: ["a": "b"])!
Suggestion:
let template = URL.Template("http://www.example.com/foo{?query,number}")!
let url = template.render(with: ["a": "b"])!
I didn't think so. Like the proposal says, this seems consistent with other APIs, e.g.: String(format:). At least to my mind, this makes more sense, for in general templates don't really render or do anything; they're something you render or act with. In this case, the URL initialises itself with a template and variables.
Oh sorry, I totally forgot to check the alternatives section.
String(format:) seems like an odd comparison. It's quite a niche API in Swift (unlike its counterparts in C and ObjC, where format-based string creation is the norm).
More generally, initializer overloads feel overused and hard to discover. URL already has 18 documented initializers, and even more privateish undocumented ones (go in a repl, type URL.init and press tab).
They also compose poorly in fluent-style method chains, though I guess that's less relevant here, where a template is less likely to be used in that style.
Any reason why URL.Template itself isn't ExpressibleByStringLiteral , so we could directly use […]
That’s an interesting thought.
The general idea with URL.Template is that a server sends you a template. You fill in the variables and use that to send requests to the server.
In your example
let url = URL(template: "http://www.example.com/foo{?query,number}", variables: ["a": "b"])!
you could have done
let url = URL(string: "http://www.example.com/foo")!
and gotten the same result. ;)
Maybe the documentation needs to be updated to more clearly state what this is intended to be used for?
But I’m not opposed to adding ExpressibleByStringLiteral. But it might be promoting usage other than what’s (originally) intended. The question is thus: should we discourage such usage or encourage it.
There’s also the question of: Why isn’t URL itself ExpressibleByStringLiteral?
For the future, the JavaScript ecosystem is in the process of standardizing on the URL Pattern Standard as part of the Minimum Common Web Platform API. This standard is useful mainly for URL pattern matching, but also going the other directionsand encoding URLs from components based on the pattern. This is a far more popular standard and would make a good counterpart to this feature.
When dealing with web tech, which is a far bigger pool than native apps, it seems like the best solution would be to standardise around the path the JS ecosystem is following.
Can we implement both standards or do we have to choose? If we have to choose then it might be best to consider that.
That standard is based upon the WHATWG URL standard. So you would either have to choose possible inconsistencies with the URL API or matching behaviour inconsistent with the web.
I thought about implementing it for WebURL. Ultimately it wasn't a huge priority, for 2 main reasons:
Very web-centric. From the standard:
Finally, the URLPattern constructor string parser does not handle some parts of the basic URL parser state machine. For example, it does not treat backslashes specially as they would all be treated as pattern characters and would require excessive escaping. In addition, this parser might not handle some more esoteric parts of the URL parsing algorithm like file URLs with a hostname. The goal with this parser was to handle the most common URLs while allowing any niche case to be handled instead via the URLPatternInit constructor.
I'm sorry, but file URLs with a hostname are "esoteric" now? As a URL library developer, this upsets me. It shows that the standard is really very much based around HTTP URLs, which... is fine for the web I guess, but I feel that a good URL library would have something more widely compatible.
Limitations of string interpolations
I think a good API for custom patterns in Swift would build up a generic type similar to a result builder, so that it can preserve type information about pattern expressions (e.g. capture this URL parameter as an Int). But, it should also support a lightweight string-interpolation syntax:
let pattern = "https://example.com/products/\(Int.self)/availability"
With result builders, you can do this kind of thing - you can have something like:
In some ways, you could see ExpressibleByStringInterpolation as an early form of transformations in Swift, that would later be greatly expanded by result builders. But result builders allow you to build up a generic type, which is much more expressive than ExpressibleByStringInterpolation allows.
If I could create a result-builder-like type out of a string interpolation, I'd be more interested in developing a pattern matching library for this stringy data format.