<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><br class=""><blockquote type="cite" class=""><div class="">On Oct 31, 2017, at 21:31, Chris Lattner via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">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:</div><div class=""><br class=""></div><div class="">1) Make it return a "PythonObject!”</div><div class="">2) Make it strict, returning a PythonObject or trapping.</div><div class="">3) Make PythonObject itself nullable internally and return a null PythonObject.</div><div class=""><br class=""></div><div class="">#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:</div><div class=""><br class="">let x = foo.bar<br class="">let y = x.thing // fails, because x implicitly promoted to PythonObject?<br class=""> </div><div class="">#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.</div></div></div></div></blockquote><div><br class=""></div><div>I agree, PythonObject-or-die is the right trade-off.</div><div><br class=""></div><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><div class=""><br class=""></div><div class="">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).</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">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!</div></div></div></blockquote><div><br class=""></div><div>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:</div><div><br class=""></div><div><font face="Menlo" class="">try Python.do {</font></div><div><font face="Menlo" class=""> let a = np.array([1, 2, 3])</font></div><div><font face="Menlo" class=""> let b = np.array([[2], [4]])</font></div><div><font face="Menlo" class=""> print(a.dot(b)) // matrix mul with incompatible shapes</font></div><div><font face="Menlo" class="">}</font></div><div><font face="Menlo" class="">catch let error as PythonException {</font></div><div><font face="Menlo" class=""> // Handle PythonError.valueError(“objects are not aligned”)</font></div><div><font face="Menlo" class="">}</font></div><div><br class=""></div><div>Python.do enables exception handling for statements in the body, declared as</div><div><font face="Menlo" class="">func `do`<T>(_ body: () throws -> T) throws -> T</font></div><div><br class=""></div><div>When we execute python-throwing statements inside a Python.do{}, PythonException gets thrown. Otherwise, it traps.</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>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.</div><div><br class=""></div><div>-Richard</div><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><br class=""></div><div class=""><pre style="overflow-x: auto; overflow-y: hidden; padding: 5px; background-color: rgb(238, 255, 204); color: rgb(51, 51, 51); line-height: 15.600000381469727px; border-top-width: 1px; border-bottom-width: 1px; border-style: solid none; border-top-color: rgb(170, 204, 153); border-bottom-color: rgb(170, 204, 153);" class=""><span class="k" style="color: rgb(0, 112, 32); font-weight: bold;">class</span> <span class="nc" style="color: rgb(14, 132, 181); font-weight: bold;">Dog</span><span class="p">:</span>
<span class="k" style="color: rgb(0, 112, 32); font-weight: bold;">def</span> <span class="nf" style="color: rgb(6, 40, 126);">__init__</span><span class="p">(</span><span class="bp" style="color: rgb(0, 112, 32);">self</span><span class="p">,</span> <span class="n">name</span><span class="p">):</span>
<span class="bp" style="color: rgb(0, 112, 32);">self</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">name</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="n">name</span>
<span class="bp" style="color: rgb(0, 112, 32);">self</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">tricks</span> <span class="o" style="color: rgb(102, 102, 102);">=</span> <span class="p">[]</span> <span class="c1" style="color: rgb(64, 128, 144); font-style: italic;"># creates a new empty list for each dog</span>
<span class="k" style="color: rgb(0, 112, 32); font-weight: bold;">def</span> <span class="nf" style="color: rgb(6, 40, 126);">add_trick</span><span class="p">(</span><span class="bp" style="color: rgb(0, 112, 32);">self</span><span class="p">,</span> <span class="n">trick</span><span class="p">):</span>
<span class="bp" style="color: rgb(0, 112, 32);">self</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">tricks</span><span class="o" style="color: rgb(102, 102, 102);">.</span><span class="n">append</span><span class="p">(</span><span class="n">trick</span><span class="p">)</span></pre><div class=""><br class=""></div></div><div class="">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.</div><div class=""><br class=""></div><div class=""> let dogClass = python_getClassByName(“Dog”) // implemented in the Python “overlay’, I guess</div><div class=""> let dog = python_createInstance(dogClass) // implemented in the Python “overlay’, I guess</div><div class=""> dog.__init__(“Brianna”) // uses CustomCallable’s callMember</div><div class=""> dog.add_trick(“Roll over”) // uses CustomCallable’s callMember</div></div></div></blockquote><div class=""><br class=""></div><div class="">I-am-not-a-python-expert, but I'd expect this to work:<br class=""><br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let dogModule = Python.import("DogModule")<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>dogModule.Dog("jckarter").add_trick("SILGenGen”)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let dog = dogModule.Dog(“Brianna”)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>dog.add_trick(“Roll over)<br class=""><br class="">or equivalently:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>let Dog = Python.import(“DogModule.Dog")<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>Dog("jckarter").add_trick("SILGenGen”)<br class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>let dog = Dog(“Brianna”)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>dog.add_trick(“Roll over)<br class=""></div></div><div class=""><br class=""></div><div class="">Seems pretty nice to me, with zero “Swift compiler knowledge of Python” required.</div><div class=""><br class=""></div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">With compiler integration, </div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>class Dog : PythonObject {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span> init(_ name: Pythonable)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span> func add_trick(_ trick: Pythonable)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div></div></blockquote><div class=""><br class=""></div><div class="">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. </div><br class=""><blockquote type="cite" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class="">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.</div></div></blockquote><br class=""></div><div class="">We don't need to make Swift better at Python than Python itself is :-)</div><div class=""><br class=""></div><div class="">-Chris</div><div class=""><br class=""></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>