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.

With all that being said, for people who are opposed to this proposal, how 
would the idea of an alternate, clearly opt-in syntax for dynamic member 
lookups change your views, if at all? I’m not sure what might provide the best 
balance of clarity and  ergonomics, but we could always revive “->”, right? :P

> On Nov 30, 2017, at 2:24 AM, Douglas Gregor via swift-evolution 
> <> wrote:
>> On Nov 26, 2017, at 10:04 PM, Chris Lattner via swift-evolution 
>> <> wrote:
>> I’d like to formally propose the inclusion of user-defined dynamic member 
>> lookup types.
>> Here is my latest draft of the proposal:
>> An implementation of this design is available here:
>> 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.
>       - Doug
> _______________________________________________
> swift-evolution mailing list
swift-evolution mailing list

Reply via email to