[swift-evolution] URL Literals

Micah Hainline micah.hainline at gmail.com
Wed Dec 28 13:44:35 CST 2016


I think the way it's set up it probably WOULD run, but it should still
probably be a compile error. I like that we have the concept of
static-string-literal in the language definition, but I'm having a bit
of a hard time tracking it through the compiler. Of course, these are
problems probably not right for this list, so I'll take them into a
bug instead.

On Wed, Dec 28, 2016 at 1:36 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
> On Wed, Dec 28, 2016 at 2:29 PM, Micah Hainline via swift-evolution
> <swift-evolution at swift.org> wrote:
>>
>> > SE-0039 says that resourceName should be a static-string-literal
>>
>> It compiles just fine for me in my project. My next question was going
>> to be do we actually need a change in the language spec, or can we
>> call fixing that a bug, I think you're answering my question for me
>> before I even had to ask it!
>
>
> I'd call that a bug. It doesn't run, and there's no reason why something not
> allowed by the grammar shouldn't be diagnosed at compile time, IMO.
>
> From _The Swift Programming Language_:
>
> GRAMMAR OF A STRING LITERAL
> string-literal → static-string-literal­ | interpolated-string-literal­
> static-string-literal → "­quoted-text­opt­"­
> quoted-text → quoted-text-item­ quoted-text­opt­
> quoted-text-item → escaped-character­
> quoted-text-item → Any Unicode scalar value except "­, \­, U+000A, or U+000D
> interpolated-string-literal → "­interpolated-text­opt­"­
> interpolated-text → interpolated-text-item­ interpolated-text­opt­
> interpolated-text-item → \(­expression­)­ | quoted-text-item­
> escaped-character → \0­ | \\­ | \t­ | \n­ | \r­ | \"­ | \'­
> escaped-character → \u­{­unicode-scalar-digits­}­
> unicode-scalar-digits → Between one and eight hexadecimal digit
>
>
>>
>> On Wed, Dec 28, 2016 at 1:20 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>> > On Wed, Dec 28, 2016 at 2:08 PM, Micah Hainline via swift-evolution
>> > <swift-evolution at swift.org> wrote:
>> >>
>> >> 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.
>> >
>> >
>> > That could be fixed with documentation. This API design was reviewed and
>> > approved as part of SE-0039:
>> >
>> > https://github.com/apple/swift-evolution/blob/master/proposals/0039-playgroundliterals.md
>> >
>> >>
>> >> 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)")```.
>> >
>> >
>> > Can you? SE-0039 says that resourceName should be a
>> > static-string-literal,
>> > which (unless I'm mistaken) should forbid interpolation.
>> >
>> >>
>> >> 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
>> >> >
>> >> _______________________________________________
>> >> swift-evolution mailing list
>> >> swift-evolution at swift.org
>> >> https://lists.swift.org/mailman/listinfo/swift-evolution
>> >
>> >
>> _______________________________________________
>> 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