[swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

Chris Lattner sabre at nondot.org
Sat Nov 11 19:27:01 CST 2017


On Nov 11, 2017, at 4:15 PM, Andrew Bennett <cacoyi at gmail.com> wrote:
> HI, this proposal looks really interesting!

Thanks!

> Clarity on the proposal's intent
> Nice cheap bridges, or lowering barriers to bridging?

The later: I’m not overly concerned about constant time performance: dynamic languages are often slow (though exceptions exist, e.g. Javascript).  So if there is a beautiful approach that works great but is a bit slower, that is fine with me.

My desire is to enable access to “any” API in Python directly from Swift with natural syntax.  This doesn’t mean it has to match Python of course: Python ranges and Swift ranges are syntactically very different, and Swift-in-Python should use Swift syntax.  That said, there are a LOT of expression level similarities between Swift and Python, so things that can be the same should be.

This proposal isn’t the only way to achieve that, of course.  I’m open to other suggestions.

> I can see this providing a nice quick interface to Python from Swift, but I'm not sure if the exposed interface will be very Swifty (you probably have a much better idea of what is Swifty ;) than I do though). It seems you want it to be possible for everything to be dynamically exposed


Right: Python APIs are not “Swifty”.  They do not use optionals or generics, use lowercase snake names, etc.  IMO, that’s perfectly fine.  Unlike the Objective-C interop in Swift - which aims to make legacy ObjC APIs feel Swifty, it is perfectly acceptable (and far less impact on the compiler) to just import Python directly into Swift.  This is actually much better for the target audience anyway.

> Is it common for the the argument labels in other languages to be open ended, or are labels typically finite? If the answer is finite, why not use a Swift method as the wrapper?

Python keyword arguments are open ended.  They get passed to the Python API as a dictionary.

> Do you want duck typing, and would it be better to expose this via a protocol?

I’m not sure how that can work, can you elaborate?

> It seems like in almost every case you could do something like this:
> 
> func myMethod<X: PythonConvertible & CanQuack, Y: PythonConvertible>(a: X? = nil, b: Y) {
>     pythonBridge.call("myMethod", arguments: ["a": X, "b": Y])
> }

The currency type is PyVal (name TBD of course), just like AnyObject for Objective-C. I’m not sure what the code above is getting at.

> It might be good to add some use-cases (a popular Python library perhaps) to the proposal where this type of bridge would be insufficient :).

There are lots of examples.  In data science, NumPy and Pandas are two examples.  The Python community is 1 or 2 orders of magnitude larger than Swift’s community and there is 25 years of code out there to interop with.  The point of this is to make it all accessible.

> It seems like this proposal pushes the responsibility of Swifty-ness and type-safety to the caller.

Yes, welcome to dynamic languages :-)

> At some point you'll have to write a type-safe bridging layer, or write your entire program in non-Swifty code ("The most obvious way to write code should also behave in a safe manner"). Is the main goal to lower the barrier to Python and other dynamic languages? or is it to provide a cheap nice Swifty bridge? I have the above concerns about the latter.

It’s the later.  Many Python APIs are already wrappers around C code, so if someone cares about investing a bunch of effort into making a great Swift API, it would generally make sense to wrap the C API in Swift, not wrap the Python API in Swift.

> Alternative sugar
> 
> Ruby has Keyword Arguments for similar sugar:
> 
> def foo(regular, hash={})
>     puts "the hash: #{hash}"
> 
> 
> I'm sure you're aware of it, but I'll explain for completeness, any trailing argument labels are stored and passed as a hash:
> 
> foo(regular, bar: "hello", bas: 123) # outputs 'the hash: [bar: "hello", bas: 123]’
Python is similar, but allows them to be intermixed with positional arguments.

> Have you considered an alternative like this? For example:
> 
> func myMethod(regular: Int, store: @argcapture [String: PythonConvertible]) -> PythonConvertible
> 
> I'm sure you have good reasons, it might make the implementation bleed out into other parts of the codebase. It would be good to include it in the proposal alternatives section though. At the moment most of the "alternatives" in the proposal just seem to be extensions to the same solution :)

I’m not sure what you’re getting at here.  The system I’ve sketched out does not incorporate Python declarations, everything is dynamic.  It is extremely simple.  This is a huge feature :-)  I think it is entirely non-scalable to do something like the ObjC importer for every language that Swift wants to interop with.

> Clarity
> Perhaps just that things are more clear to me now
> 
> If my extrapolation is correct a user will implement a single type that will allow a subset of a good portion of another language to be exposed (object method and property bridging). I'm guessing that the dynamic member proposal you're planning will not work with methods, it will require a property, I think this helps explain some of the motivations. It might be nice to have a more complete example that includes dynamic members. I didn't find it clear from the proposal that it would only be necessary to implement this protocol once per language.

I’m sorry, I don’t understand what you mean.

-Chris


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20171111/9b6f1bc6/attachment.html>


More information about the swift-evolution mailing list