What is your evaluation of the proposal?
Enthusiastic +1. I like it as is.
I am opposed to all the strategies listed under “Reducing Potential Abuse” in the proposal.
In the future, I would very much like to see lookup keys other than String, as Brent suggested. However, the proposal is worthwhile even without that feature.
I would also like lookups to be able to throw, as Matthew wanted. However, because of the technical limitations Chris laid out, I would not want this proposal to be delayed for that.
It is a little troubling that the feature will not support keypaths. My gut says that will need attention soon. However, as Chris says, we should have a use case in hand.
Is the problem being addressed significant enough to warrant a change to Swift?
Yes, there are two independent problems each of which could justify this feature:
- Dynamic language interop opens many exciting doors for Swift — but only if it is syntactically ergonomic. It currently is not. No, not even string subscripts. (Try actually writing out some Python API calls with it; it's a hot information design mess. And yes, code syntax and formatting is a form of information design.) Statically generated API bindings might be feasible (and preferable) in some cases, but many dynamic APIs are not even knowable at compile time. Wrapper generation is at best a partial solution.
- Unstructured data access and config DSLs, while often best served by clever use of statically typed constructs (enums enums enums), can make good use of dynamism even in an otherwise statically typed language. In particular, I can imagine this being very nice for things like routing config which (1) is parsed and checked in its entirety at startup and (2) benefits from concise references by name to the things which it has configured. The cumbersome SwiftPM manifest format might even profit from this proposal.
Yes, I’m sure that some people (likely including me) will go too far experimenting with #2. And when those experiments turn out to be bad, the community will abandon them — if the original author doesn’t ditch them first. (Remember in Swift’s early days the torrent of goofy novelty operator libraries? That ran its course, the few that were actually useful survived, and the language landscape has only improved since then.)
Does this proposal fit well with the feel and direction of Swift?
This is the contentious one, isn’t it?
I’ve heard a number of concerns about this — some reflexive sneering at dynamic languages, some entirely valid. Some have made me think hard. None have swayed me. My thoughts on the greatest hits:
“It’s hard to spot dynamic calls in code!”
Two words: syntax highlighting.
Swift is already a language that relies heavily on either static analysis from tools or static investigation by the developer to be understood. Its unusually extensive type inference alone already makes it incredibly difficult to know without the help of a tool what the type of $1
is or what type .foo
belongs too.
“I don’t want to use it, even by accident!”
Fair enough. Set a linter rule. Wish granted!
“People will write terrible code with it!”
This is entirely true. They will also write terrible code without it.
Most of the concerns I’ve heard expressed could be addressed by sensible developers and good tools. The latter are feasible; the former no language can enforce.
“This proposal undermines the compile-time safety we’ve come to expect from Swift!”
This is the one objection that carries real weight for me. I was concerned about it at first too.
The thing that swayed me was Chris giving examples of other things that are not checked at compile time, yet have no syntactic “danger” marker at the usage site:
- array subscripting,
- integer overflow, and
- invoking a method that can cause a
fatalError
or precondition failure, which can of course be any method.
AnyObject dispatch has come up a lot in this discussion, but it’s a bit of a red herring: obscure, rarely used, a necessary hack. The bullet points above are core language features that we use all the time, and none of them involve any of the syntactic markers or other usage obstacles people have proposed in this thread. Not one.
On objective analysis, Swift is full of runtime dangers. Yet I’ve always felt like it is an especially safe language, in a way that is closer to ML than C. Why? I’ll dredge up what I posted back in early December; it still stands now:
Sentiments like this subjectively fit the experience of using Swift. When using the language in practice, it’s fairly clear to a mindful developer which operations carry some inherent level of danger, what kind of danger that is, how to reason about it, and how to mitigate it. (Usually, anyway.)
Having all had this pleasant experience, I think we may be too quick to look for the explanation in the design of the language itself. We fail to notice that it comes not from the language alone, but from the whole ecosystem that surrounds it: standard library design, naming conventions, tools, libraries, culture, Erica’s books, etc.
Optionals present themselves as a specially privileged part of the language; withUnsafeBytes
presents itself as a library call using existing language features. But both share a similar definitively Swift-ish aesthetic in how they guide our attention, and how they circumscribe programmer error while leaving the language ergonomic and situationally adaptable.
[Chris’s] reminder is a good one: Swift already does not have, and never has had, a sense of safety that depends on Haskell-like strictness in the language itself. The design question at hand in this thread thus becomes not “how can we prevent dynamic dispatch from ruining everything” but rather “how can we introduce this new element in a way that does not disrupt the ecosystem.” In considering that, we’d do well to remember the long-established language features that have so far failed to ruin everything despite their “impurity.”
Underlying many objections is a fear that creeping dynamism will ruin the whole neighborhood and destroy all we hold dear. I don’t think that will happen. I see Chris’s examples of other unmarked dangerous behavior, and the line of thought above, as an optimistic answer to that fear: Swift’s Swiftiness has always depended on good judgement. It has always depended on an ecosystem that extends beyond the language features, and in some particular cases even pushes toward mindfulness and safety in spite of language features. A language feature alone will not erase the good sense of the language’s stewards, or poison its community.
I think there is a place for dynamic dispatch in Swift. There are a few problems where it is the right answer. And I’m sure that the ecosystem can integrate it in a way that does not fundamentally alter what we like about Swift. This is a language that’s managed to integrate raw memory access, for heaven’s sake, and still feel “closer to ML than C!” If it can do that, it can certainly withstand the far smaller disturbance in the force of what Chris is proposing.
How much effort did you put into your review?
More than was wise.