> On Nov 30, 2017, at 1:01 PM, Zach Wolfe <[email protected]> wrote:
>
> 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.
- Doug
>
> On Nov 30, 2017, at 2:24 AM, Douglas Gregor via swift-evolution
> <[email protected] <mailto:[email protected]>> wrote:
>
>>
>>
>>> On Nov 26, 2017, at 10:04 PM, Chris Lattner via swift-evolution
>>> <[email protected] <mailto:[email protected]>> 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
>>> <https://gist.github.com/lattner/b016e1cf86c43732c8d82f90e5ae5438>
>>> https://github.com/apple/swift-evolution/pull/768
>>> <https://github.com/apple/swift-evolution/pull/768>
>>>
>>> An implementation of this design is available here:
>>> https://github.com/apple/swift/pull/13076
>>> <https://github.com/apple/swift/pull/13076>
>>>
>>> The 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
>> [email protected] <mailto:[email protected]>
>> https://lists.swift.org/mailman/listinfo/swift-evolution
>> <https://lists.swift.org/mailman/listinfo/swift-evolution>
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution