Sent from my iPhone
> On Nov 30, 2017, at 00:24, 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
>> https://github.com/apple/swift-evolution/pull/768
>>
>> An implementation of this design is available here:
>> 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. 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.
Agreed.
In particular, I’d rather take the time to design a foundation for Swift
interoperating with any given language, than have one mechanism for Python,
another for Ruby, yet another for C++, etc.
- Dave Sweeris
_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution