[swift-evolution] URL Literals

Tony Allevato allevato at google.com
Sat Dec 17 10:52:46 CST 2016


If folks want to go down this path, it:

* shouldn't require compiler magic
* shouldn't be restricted to specific types
* should be something that anyone can take advantage of in types that they
write.

The most general approach that jumps immediately to my mind is letting
users write code in a restricted subset of the language that would be
evaluated at statically at compile time. It's getting into C++ "constexpr"
territory, but I wouldn't want to settle for something that tightly couples
special behavior to just a few types.

Quick back of the napkin sketch, I haven't thought too much about syntax
details yet:

struct URL: ExpressibleByStringLiteral {
  // the #, or something similar, indicates this
  // is compile-time evaluation
  #init?(_ stringLiteral: StaticString) {
    // validate the string. We'd be able to use
    // loops and access individual characters
    // in the static string... regexes would be
    // trickier.
    if valid {
      // if we get here, everything we did
      // will essentially "collapse" to this
      // initializer call in the generated code
      self.init(...)!
    } else {
      return nil
      // need a way of emitting a more
      // informational error message?
    }
  }
}

There's still a lot of open questions to think through, like should this
only apply to literal conversions or any initializer signature where the
arguments' value can be known at compile time, but I wanted to toss out a
seedling of a different idea. I also don't know how much would have to
change within the compiler to provide this level of compile-time evaluation.


On Sat, Dec 17, 2016 at 5:57 AM Step C via swift-evolution <
swift-evolution at swift.org> wrote:

> Do you have a treatment in mind?
>
> Perhaps the compiler recognizes types/initializers it can check at compile
> time (how?). Then it could synthesize non-failable initializers.
>
> Or would the author write a non-failable init with some type of annotation
> that the parameters must be literals? (Here I am using literals to mean
> values that are understood by the compiler.)
>
> - Step
>
> On Dec 16, 2016, at 9:46 PM, Xiaodi Wu via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Actually, a syntax similar to the one I described was considered for
> selectors; it was rejected in favor of #selector because something like
> Selector(Foo.bar) is apparently more difficult to implement, and the core
> team said that "on balance, we didn't want to introduce type system
> complexities for relatively rare ObjC interop features".
>
> However, I would think that the general issue of compiler help to indicate
> when certain initializers are guaranteed to fail is the opposite of a
> "relatively rare interop feature" and deserves perhaps a more holistic
> treatment rather than a selector-like quick-fix for URLs only.
>
> On Fri, Dec 16, 2016 at 20:33 Micah Hainline <micah.hainline at gmail.com>
> wrote:
>
> Absolutely. Good breakdown of the issues. I will draw a parallel with
> #selector though for past precedent. It wouldn't have been much different
> to just use the string-based Selector creation instead of creating a new
> language feature and just validate string literals in that context to
> verify they're okay in much the same way you describe here. There was value
> in breaking that out differently though, partly because it makes very clear
> what will and what will not be validated.
>
> I don't think force-unwrapping is exactly an anti pattern, but it is one
> of the less desirable patterns, and I do think it should be avoided where
> cleanly possible.
>
> On Dec 16, 2016, at 8:14 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Fri, Dec 16, 2016 at 8:00 PM, Micah Hainline <micah.hainline at gmail.com>
> wrote:
>
> We'll have to agree to disagree about the value of getting rid of the
> force-unwrap.
>
>
> I suppose we may have to. But I hope to have convinced you that what
> you're really getting at here are two issues that can be separated. The two
> are:
>
> 1. The developer experience of using failable initializers invoked with
> hardcoded arguments is sub-par. For URL, or for any other type where
> success or failure of initialization is determined entirely by the
> arguments passed in, it would be nice to have the compiler tell you _at
> compile time_ if the hardcoded arguments are guaranteed to cause the
> initializer to return nil. I think this is quite an insightful point.
>
> 2. You do not like working with force unwrapping. While certainly entitled
> to that opinion, I do not think this opinion alone (since it is separable
> from (1)) can justify additions or subtractions to the language. Either
> force unwrapping is a legitimate part of the language--that is, the
> community that designs Swift can agree on specific patterns where its use
> is considered best practice--or it is an anti-pattern that should be
> deprecated and eventually removed. It cannot be a lingering yet fully
> supported first-class anti-pattern that we design standard and core library
> APIs actively to avoid.
>
>
> On Dec 16, 2016, at 7:54 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Fri, Dec 16, 2016 at 7:44 PM, Micah Hainline <micah.hainline at gmail.com>
> wrote:
>
> Noted, but again while force-unwrapping it is the best we have,
> compile-time checking would be even better.
>
>
> Sure, I'm certainly not opposed to flagging more errors at compile time.
> But it's possible to do that without adding new syntax to the language,
> which (just MHO) is rarely the best solution when a good alternative exists.
>
> Here, for instance, one could add compiler magic that warns at compile
> time that `URL(string: "notavalidurl")!` is guaranteed to fail. That could
> be a diagnostics/QoI improvement that almost certainly wouldn't require
> going through the evolution process.
>
> What I was trying to point out is that I agree with Derrick that the
> _spelling_ `URL(string: "https://example.com/")!` is perfectly fine and
> not in need of improvement, and that I disagree strongly that force
> unwrapping is problematic as a matter of style.
>
> On Dec 16, 2016, at 7:30 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Fri, Dec 16, 2016 at 7:01 PM, Micah Hainline <micah.hainline at gmail.com>
> wrote:
>
> It's not super strong, but it's as strong as the URL type itself.
>
> Even if I do checking related to the resource being unavailable, I also
> have to do checking to account for the possibility of a nil URL. The two
> checks aren't closely related.
>
>
> When you use a URL, what would you do differently when a resource is
> unavailable versus when the URL is malformed, especially if you're
> hardcoding the URL?
>
> It does help to have one of them accounted for by the compiler if possible.
>
> I'm trying to teach some less experienced developers to think of
> force-unwrapping as a code smell,
>
>
> There have been a few people who have said a similar thing on the list,
> but I don't think this is the official line about force-unwrapping. Force
> unwrapping is an explicitly supported part of the language that has its
> uses. If you *know* at the time of writing that a failable initializer
> should never fail, then `!` is an expressive, clear, concise, entirely
> appropriate, and I would even say the *best* way of indicating that to your
> reader.
>
> It should be noted that `let url = URL(string: "http://example.com/")!`
> is one example of this usage, but not at all the only one. I have
> previously written, for example, `"L".cString(using: .utf8)!`. This is also
> no code smell, as what I'm doing is stating my absolute confidence (and
> indicating that confidence to the reader) that the letter L can be encoded
> using UTF-8.
>
> but it's not the best to have to say "except for URLs". I realize the
> utility of the proposed change is reasonably small, but I also think it's
> purely additive and consistent with the rest of the language. šŸ™‚
>
> On Dec 16, 2016, at 6:45 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
> On Fri, Dec 16, 2016 at 5:54 PM, Micah Hainline via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> True, but it's not at all about brevity, it's about type-safety and
> getting compile-time checking rather than runtime checking of the validity
> of the URL structure.
>
>
> While I understand that what you're after is compile-time checking of
> validity, I'm not convinced that it is materially useful. I also don't see
> how it's contributing to type safety. Perhaps you could illuminate what use
> case has persuaded you of these things? Here's my thinking:
>
> Nine times out of ten when I mistype a URL, or paste only a fragment of a
> URL, it's a mistake that results in a plausible but unintended URL and a
> compile-time check for validity will not help at all. To guard against such
> an error, I need to write tests anyway and could never depend on the
> compiler. In fact, I'd imagine that doing anything useful with a URL--even
> a hardcoded one--will require some thought as to how to deal with error
> handling at runtime. How is it helpful to have only the lowest bar (a
> technically valid URL format) ensured at compile time instead of runtime?
> By contrast, Swift selectors help to guarantee that any particular function
> I'm referring to actually exists; when that is ensured at compile time, I
> know it will be the case at runtime. There's no corresponding guarantee by
> having a compile-time check for URL validity that the resource pointed to
> will actually exist. That the nonexistent resource was denoted by a string
> that had the correct format of a URL is cold comfort, no?
>
>
> On Dec 16, 2016, at 5:50 PM, Derrick Ho <wh1pch81n at gmail.com> wrote:
>
> let url = URL(string: "https://example.com")!
>
> let url = #url("https://example.com")
>
> Are not that different in length. It really isn't saving you much.
>
> I suppose you can try overloading an operator to get something to the
> effect you want.
> On Fri, Dec 16, 2016 at 6:19 PM Micah Hainline via swift-evolution <
> swift-evolution at swift.org> wrote:
>
> Exactly! It's not an earth-shattering pain, but it would be nice to have
> clean type safety there.
>
>
>
>
>
> > On Dec 16, 2016, at 4:01 PM, Charlie Monroe <charlie at charliemonroe.net>
> wrote:
>
>
> >
>
>
> >
>
>
> >>> On Dec 16, 2016, at 10:05 PM, Charles Srstka via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> >>>
>
>
> >>> On Dec 16, 2016, at 2:46 PM, Micah Hainline via swift-evolution <
> swift-evolution at swift.org> wrote:
>
>
> >>>
>
>
> >>> I would like to be able to create a URL literal that is compile-time
>
>
> >>> checked for correct format. This would help avoid code like this:
>
>
> >>>
>
>
> >>>  let url: URL = URL(string: "https://example.com")!
>
>
> >>>
>
>
> >>> The cleanest way I can think of doing that would be to introduce a new
>
>
> >>> macro structure similar to #selector, though I'm open to other ideas.
>
>
> >>> I would think it should take a quoted literal string to avoid
>
>
> >>> problems. That would look like this:
>
>
> >>>
>
>
> >>>  let url: URL = #url("https://example.com")
>
>
> >>>
>
>
> >>> What does everyone think of that idea?
>
>
> >>> _______________________________________________
>
>
> >>> swift-evolution mailing list
>
>
> >>> swift-evolution at swift.org
>
>
> >>> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
> >>
>
>
> >>
>
>
> >> Iā€™d like to see something like that for file path URLs. For something
> so commonly used, URL(fileURLWithPath:) is obnoxiously verbose.
>
>
> >>
>
>
> >> Charles
>
>
> >
>
>
> > Yes, but it's not a nullable initializer. With URL(string:) the
> incredible pain is that even compile-time URLs to your own website are
> nullable URL? and you need to force-unwrap them.
>
>
> >
>
>
> >>
>
>
> >> _______________________________________________
>
>
> >> 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
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
> _______________________________________________
> 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
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20161217/8cb3ef6d/attachment.html>


More information about the swift-evolution mailing list