[swift-evolution] URL Literals

Micah Hainline micah.hainline at gmail.com
Wed Dec 28 13:08:46 CST 2016

As an aide to learning I've been playing around with implementation of
some of these concepts in the compiler and a few things popped up that
I'm not happy with.

First, regarding the way #fileLiteral works, it necessitates the
addition of URL.init(fileReferenceLiteralResourceName:) which takes a
string but does not return an optional value. Fine, except that I
don't have to call #fileLiteral in my code to use that constructor, I
can also use it directly. While I could get compile-time checking on
the #fileLiteral, I can't on the direct constructor. Additionally, I
could use the direct constructor with any String, not just literals.
Internally that will call ```self = Bundle.main.url(forResource: name,
withExtension: nil)!``` and crash at runtime if it's not found.
Clearly we do not intend that init to be called directly, but that
isn't clear to new Swift user Jude Doe, who discovers the API as xe
autocompletes from Xcode.

The second problem comes from String Interpolation. It's a basic
problem I think with anything that extends the concept of the
string_literal with additional requirements that need to be checked at
compile-time. Right now I can put in something like
```#fileLiteral(resourceName: "\(myString)")```. While at one level it
might seem nice to be able to construct this sort of thing, it's not
at all nice from a validation perspective.

I think this has to be solved at a higher level, in the Lexer, making
a url literal a concept at that level, and fundamentally NOT a string
literal underneath, even if they shared some similar constructs.

The Lexer would be able to see #url("https://\(host)") and say
"Invalid escape sequence in literal, \( is not understood as a url".
In fact, the URL literal should probably not need ANY escape sequences
or even the concept of escape sequences, since a double-quote is not a
legal character in a URL.

I definitely think we should take this opportunity to identify that we
do NOT want to use string literal as it currently stands as a base
construct for other literal types. Quite possibly there's another,
more restricted concept that we can draw out of string literal that
would make a good base construct, but certainly not a string literal
with interpolation.

On Wed, Dec 28, 2016 at 8:01 AM, Jonathan Hull via swift-evolution
<swift-evolution at swift.org> wrote:
> On Dec 27, 2016, at 11:46 AM, David Sweeris <davesweeris at mac.com> wrote:
> On Dec 22, 2016, at 11:39 PM, Jonathan Hull <jhull at gbis.com> wrote:
> On Dec 20, 2016, at 12:29 PM, David Sweeris <davesweeris at mac.com> wrote:
> On Dec 20, 2016, at 2:11 AM, Jonathan Hull via swift-evolution
> <swift-evolution at swift.org> wrote:
> Yes, I agree.  I am excited to see what happens in phase 2.
> What I am suggesting here is slightly different. Basically being able to use
> RegEx (with capture groups) as a shorthand for a type composed of base
> literals. For example: (StringLiteral, [IntegerLiteral]). Named capture
> groups could even map to a dictionary literal.  I am using “RegEx goes Here”
> to represent RegEx in the examples below, but hopefully it will get it’s own
> literal type in Xcode (Imagine that replacing it here).
> func foo( _ param: “RegExGoesHere”) {…} //Definition uses a RegEx where the
> type would normally be
> foo(“my parseable string") //Calling with a string literal
> In this case, ‘param’ takes a string literal when called but the compiler
> converts it to a tuple of literals based on the regEx supplied and passes
> that tuple the function. The type/structure of the tuple is defined by the
> capture groups in the RegEx
> The parameter above would only allow string literals to be passed in, and
> would give a compiler error if you tried to pass a variable or if the string
> didn’t conform to the supplied RegEx.  To allow passing String variables you
> would have to add either ‘?’ or ‘!’ after the RegEx definition to handle the
> case where the value doesn’t conform.
> func foo( _ param: “RegExGoesHere”?) {…} //‘param' is nil if RegEx fails
> foo(myStringVar) //Calling
> func bar( _ param: “RegExGoesHere”!) {…} //fatal error if RegEx fails
> When a variable is passed, the RegEx is performed at runtime instead of
> compile time.
> Once you have this, the syntax to add new literal types/initializers falls
> out virtually for free.
> Is “RegExGoesHere” where the regex pattern goes, or where the string you’re
> trying to match goes? If it’s the latter, where does the pattern go? If it’s
> the former, where does the string you’re trying to match go?
> “RegExGoesHere” is where the pattern goes (instead of the type).  The string
> you are trying to match gets passed in as the parameter (e.g. “my parseable
> string”).
> Ah, ok, I think I understand what you’re saying now... You’re suggesting
> that instead of defining a custom type that conforms to “RegExLiteral” (or
> some other mechanism) and using that as the parameter’s type, you put your
> regex pattern as the type directly?
> Yes.  It is admittedly an advanced feature, but I think it would be a useful
> one.
> Thanks,
> Jon
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list