> On Oct 31, 2017, at 21:31, Chris Lattner via swift-evolution 
> <[email protected]> wrote:
> 
> Also, for sake of discussion, we’d have to figure out what the type of 
> MemberLookupResultType would be for Python.  I can see several choices:
> 
> 1) Make it return a  "PythonObject!”
> 2) Make it strict, returning a PythonObject or trapping.
> 3) Make PythonObject itself nullable internally and return a null 
> PythonObject.
> 
> #1 matches Python semantics directly, because it allows clients who care to 
> check, but those who don't can ignore it.  The only problem I anticipate is 
> that it will break things like:
> 
> let x = foo.bar
> let y = x.thing   // fails, because x implicitly promoted to PythonObject?
>  
> #3 is gross and cuts against lots of things in Swift (recall when 
> UnsafePointer itself was implicitly nullable, lets not go back to those bad 
> old days).  I think that #2 is the least bad tradeoff.

I agree, PythonObject-or-die is the right trade-off.

> 
> Yes, something like this is what I had in mind, but I think that functionName 
> should only be required to be StringLiteralConvertible (no need to actually 
> synthesize a real swift string).
> 
> 
> Since you bring it up, Python exceptions will be annoying - As with other 
> languages, Python can throw from an arbitrary expression.  Modeling 
> everything as throws in Swift would be super-annoying and unergonomic for the 
> programmer, because we'd require 'try' everywhere.  Thoughts on what to do 
> about that are welcome!

Requiring ‘try’ on every statement is annoying, but not having the ability to 
catch python exceptions is annoying too. We could probably make python 
exception handling an opt-in feature. For example:

try Python.do {
    let a = np.array([1, 2, 3])
    let b = np.array([[2], [4]])
    print(a.dot(b)) // matrix mul with incompatible shapes
}
catch let error as PythonException {
    // Handle PythonError.valueError(“objects are not aligned”)
}

Python.do enables exception handling for statements in the body, declared as
func `do`<T>(_ body: () throws -> T) throws -> T

When we execute python-throwing statements inside a Python.do{}, 
PythonException gets thrown. Otherwise, it traps.

The ‘Python.do’ function would ask the python overlay to enter an 
"error-catching" state when executing the body closure. We make PythonObjects 
internally nullable, but guarantee that they are non-null (or trap) when the 
overlay is not in the “error-caught” state. When a python exception is thrown 
in the error-catching state, the overlay enters the error-caught state and 
propagates null through any python computation in the body closure. After the 
body is executed, throw that python exception.

However, if there’s a throwing Swift statement after the throwing python 
statement in the body, the python exception won’t be caught first… So having 
the body as a non-throwing closure may be a better idea.

-Richard

> 
>> 
>> class Dog:
>> 
>>     def __init__(self, name):
>>         self.name = name
>>         self.tricks = []    # creates a new empty list for each dog
>> 
>>     def add_trick(self, trick):
>>         self.tricks.append(trick)
>> 
>> With your don’t-modify-the-compiler approach, how can I create a Dog 
>> instance and add a trick? I probably need to look up the class by name, call 
>> __init__ manually, etc.
>> 
>>   let dogClass = python_getClassByName(“Dog”) // implemented in the Python 
>> “overlay’, I guess
>>   let dog = python_createInstance(dogClass)  // implemented in the Python 
>> “overlay’, I guess
>>   dog.__init__(“Brianna”)      // uses CustomCallable’s callMember
>>   dog.add_trick(“Roll over”)  // uses CustomCallable’s callMember
> 
> I-am-not-a-python-expert, but I'd expect this to work:
> 
>       let dogModule = Python.import("DogModule")
>       dogModule.Dog("jckarter").add_trick("SILGenGen”)
>       let dog = dogModule.Dog(“Brianna”)
>       dog.add_trick(“Roll over)
> 
> or equivalently:
> 
>       let Dog = Python.import(“DogModule.Dog")
>       Dog("jckarter").add_trick("SILGenGen”)
>       let dog = Dog(“Brianna”)
>       dog.add_trick(“Roll over)
> 
> Seems pretty nice to me, with zero “Swift compiler knowledge of Python” 
> required.
> 
> 
>> With compiler integration, 
>> 
>>      class Dog : PythonObject {
>>        init(_ name: Pythonable)
>>        func add_trick(_ trick: Pythonable)
>>      }
> 
> Something like this is possible, but would be substantially more work, be 
> substantially more invasive, and would set the precedent that every other 
> dynamic language would get support hacked directly into Swift.  The only 
> reason I can see this being useful is if we wanted to support the optional 
> typing annotations in Python.  While this would be "nice to have", I think 
> the cost/benefit tradeoff involved is totally wrong for Swift. 
> 
>> With either the true “Python importer” solution or this code-generation 
>> solution, you at least get some level of code completion and basic sanity 
>> checking “for free”. In other words, you get some of the benefits of having 
>> a statically-type-checked language while still working on dynamic Pythonable 
>> types.
> 
> We don't need to make Swift better at Python than Python itself is :-)
> 
> -Chris
> 
> 
> _______________________________________________
> swift-evolution mailing list
> [email protected]
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to