Doug and others have brought up some great points, and I think Doug’s idea
of a common infrastructure for importing declarations from other languages
is _extremely_ attractive for the long-term future of Swift.However, unlike this proposal, that will (I imagine as a non-compiler
engineer) be a colossal undertaking, and as such it’s not going to make it
into Swift 5, or possibly even 6 or 7. I understand, then, Chris’s (and
other’s) desire to start interfacing with Python code now, not later. For
me, far and away the biggest problem with this proposal (and the only
outright deal-breaker) is that dynamic member lookups do not differentiate
themselves in any way from statically-checked member lookups syntactically.
I don’t object as strongly as others to the idea of adding this kind of
dynamism to the language, but if it’s going to be there, it should not be
possible to slightly misspell a static member name and end up with an
unexpectedly dynamic member that may or may not fail at compile-time.As noted at the end of my message, I think one can write a Swift library
to make working with the Python runtime much easier, and write a wrapper
generator that produces Swift APIs from Python code that use said Swift
library.That might be true for Python; I’m quite certain it’s not the case for
Ruby or JS as they exist in the wild. However…At the risk of stating a universally unpopular opinion, beyond interop
with dynamic languages such as Python, there’s also value in dynamic member
lookup for •purely Swift-centric• reasons.I say this with mixed feelings. I share Douglas’s concerns about breaking
Swift’s safety bubble. I like it that the language generally makes it clear
•at the point of use• which language features have runtime pitfalls that
the compiler cannot check. The points where this is not true of the
language (e.g. array subscripts) always feel a bit gritty between the teeth.There can, however, be great value in constructing type membership at
runtime. The ergonomic access to JSON that’s been discussed in this
proposal is nothing to sneeze at. Dynamic languages make for lovely DSLs in
a way that fully statically type checked languages never do. Things like
Rails’s programmatically generated named routes (e.g. “user_post_path(id)”
because routing configuration created a user resource with nested posts)
are possible to approximate with statically typed approaches — but only
clumsily, never with the same expressiveness and concision.
I'm sorry but, no. Please, don't bring ruby magic and "lovely DSL" found
in dynamic languages into swift right now. I've had my share of dynamic
programming as well, mostly python and javascript, and i think it's now
pretty clear they make wonderful 20 lines scripts, but horrible 20 folders
projects languages. Typescript and python type annotations aren't taking
off for no reason (and if you look even further, in the case of client-side
javascript, the "hype" is going to language even stricter like elm).
The "JSON parsing" example given in the proposal is actually a perfect
example of what could go wrong if we were to add that to swift : people
will have the choice of declaring an actual struct as well as parsing
annotations (and by doing so, create an actual *documentation* and
"contract", somewhere, of what to expect). Or they'll just use dynamic
magic, and spread field accesss looking like real properties a little
everywhere in the code. And i know very well what choice they'll take.
On the other hand, if we wanted to add some "magic like" behavior, i have
an intuition (but that's just what it is, since i'm not coding compilers
for a living), that having a proper macro systems, or higher order types,
as well as good enough tooling to generate bridges to other languages, we
could be both type safe, and terse.
Actually, if people really feel the urge the interface with dynamic
language with a "dynamic feel", i'm not even sure something like a
"SwiftScript" fork wouldn't be a better idea than just try to cram python
behaviors into a statically typed language.
···
On Thu, Nov 30, 2017 at 10:48 PM, Paul Cantrell via swift-evolution < swift-evolution@swift.org> wrote:
On Nov 30, 2017, at 3:40 PM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
On Nov 30, 2017, at 1:01 PM, Zach Wolfe <zacharyreidwolfe@gmail.com> > wrote:
I don’t mean to sneeze at the downside of dynamic typing either. They too
are nothing to sneeze at. I’ve spent many years on both sides of the
dynamic divide, and all I see is difficult tradeoffs.Swift so far has said that dynamism isn’t worth the tradeoffs; it’s
aggressively avoided even robust runtime reflection, much less dynamic
dispatch. That may indeed be the right call for the language — but I’m not
easily convinced there isn’t room to open the door wider.I think of Chris’s post back in the early days of this list about the
“programmer model” the language creates, and wonder if there’s a way we
can’t make a model that leaves the door open to this kind of dynamic
dispatch where it makes sense for the people and situation at hand, while
still staying true to the language’s spirit of “compile-time safety by
default, exceptions to that by intent at point of use.”Opening the door to dynamism might take some of the flavor of the way the
language currently handles unsafe memory access: it’s possible and even
reasonably ergonomic, but you always know when you’ve crossed the Rubicon
into Dangerland.Cheers,
Paul
- Doug
On Nov 30, 2017, at 2:24 AM, Douglas Gregor via swift-evolution < > swift-evolution@swift.org> wrote:
On Nov 26, 2017, at 10:04 PM, Chris Lattner via swift-evolution < > swift-evolution@swift.org> wrote:
I’d like to formally propose the inclusion of user-defined dynamic member
lookup types.Here is my latest draft of the proposal:
https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438
DynamicMemberLookup proposal by lattner · Pull Request #768 · apple/swift-evolution · GitHubAn implementation of this design is available here:
https://github.com/apple/swift/pull/13076The implementation is straight-forward and (IMO) non-invasive in the
compiler.I think better interoperability with Python (and other OO languages in
widespread use) is a good goal, and I agree that the implementation of the
feature described is straight-forward and not terribly invasive in the
compiler.However, I do not think this proposal is going in the right direction for
Swift. I have objections on several different grounds.*Philosophy*
Swift is, unabashedly, a strong statically-typed language. We don’t allow
implicit down casting, we require “as?” so you have to cope with the
possibility of failure (or use “as!” and think hard about the “!”). Even
the gaping hole that is AnyObject dispatch still requires the existence of
an @objc declaration and produces an optional lookup result, so the user
must contend with the potential for dynamic failure. Whenever we discuss
adding more dynamic features to Swift, there’s a strong focus on
maintaining that strong static type system.IMO, this proposal is a significant departure from the fundamental
character of Swift, because it allows access to possibly-nonexistent
members (as well as calls with incorrect arguments, in the related
proposal) without any indication that the operation might fail. It’s easy
to fall through these cracks for any type that supports
DynamicMemberLookupProtocol—a single-character typo when using a
DynamicMemberLookupProtocol-capable type means you’ve fallen out of the
safety that Swift provides. I think that’s a poor experience for the Python
interoperability case, but more on that in the Tooling section below.While we shouldn’t necessarily avoid a feature simply because it can be
used distastefully, consider something like this:public extension NSObject : DynamicMemberLookupProtocol,
DynamicCallableProtocol { … }that goes directly to the Objective-C runtime to resolve member lookups
and calls—avoiding @objc, bridging headers, and so on. It’s almost
frighteningly convenient, and one could imagine some mixed
Objective-C/Swift code bases where this would save a lot of typing (of
code)… at the cost of losing static typing in the language. The presence of
that one extension means I can no longer rely on the safety guarantees
Swift normally provides, for any project that imports that extension and
uses a subclass of NSObject. At best, we as a community decide “don’t do
that”; at worse, some nontrivial fraction of the community decides that the
benefits outweigh the costs (for this type or some other), and we can no
longer say that Swift is a strong statically-typed language without adding
“unless you’re using something that adopts DynamicMemberLookupProtocol”.*Tooling*
The Python interoperability enabled by this proposal *does* look fairly
nice when you look at a small, correctly-written example. However,
absolutely none of the tooling assistance we rely on when writing such code
will work for Python interoperability. Examples:* As noted earlier, if you typo’d a name of a Python entity or passed the
wrong number of arguments to it, the compiler will not tell you: it’ll be a
runtime failure in the Python interpreter. I guess that’s what you’d get if
you were writing the code in Python, but Swift is supposed to be *better*
than Python if we’re to convince a community to use Swift instead.
* Code completion won’t work, because Swift has no visibility into
declarations written in Python
* Indexing/jump-to-definition/lookup documentation/generated interface
won’t ever work. None of the IDE features supported by SourceKit will work,
which will be a significant regression for users coming from a
Python-capable IDE.Statically-typed languages should be a boon for tooling, but if a user
coming from Python to Swift *because* it’s supposed to be a better
development experience actually sees a significantly worse development
experience, we’re not going to win them over. It’ll just feel inconsistent.*Dynamic Typing Features*
It’s possible that the right evolutionary path for Swift involves some
notion of dynamic typing, which would have a lot of the properties sought
by this proposal (and the DynamicCallableProtocol one). If that is true—and
I’m not at all convinced that it is—we shouldn’t accidentally fall into a
suboptimal design by taking small, easy, steps. If we’re to include
dynamic-typing facilities, we should look at more existing practice—C#
‘dynamic' is one such approach, but more promising would be some form of
gradual typing a la TypeScript that let’s one more smoothly (and probably
explicitly) shift between strong and weak typing.*How Should Python Interoperability Work?*
Going back to the central motivator for this proposal, I think that
providing something akin to the Clang Importer provides the best
interoperability experience: it would turn Python declarations into *real*
Swift declarations, so that we get the various tooling benefits of having a
strong statically-typed language. Sure, the argument types will all by
PyObject or PyVal, but the names are there for code completion (and
indexing, etc.) to work, and one could certainly imagine growing the
importer to support Python’s typing annotations
<https://docs.python.org/3/library/typing.html>\. But the important part
here is that it doesn’t change the language model at all—it’s a compiler
feature, separate from the language. Yes, the Clang importer is a big
gnarly beast—but if the goal is to support N such importers, we can
refactor and share common infrastructure to make them similar, perhaps
introducing some kind of type provider infrastructure to allow one to write
new importers as Swift modules.In truth, you don’t even need the compiler to be involved. The dynamic
“subscript” operation could be implemented in a Swift library, and one
could write a Python program to process a Python module and emit Swift
wrappers that call into that subscript operation. You’ll get all of the
tooling benefits with no compiler changes, and can tweak the wrapper
generation however much you want, using typing annotations or other
Python-specific information to create better wrappers over time.- Doug
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution