<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 &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; 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. &nbsp;I can see several choices:</div><div class=""><br class=""></div><div class="">1) Make it return a &nbsp;"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&nbsp;allows clients who care to check, but those who don't can ignore it. &nbsp;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 &nbsp; // fails, because x implicitly promoted to PythonObject?<br class="">&nbsp;</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). &nbsp;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&nbsp;an arbitrary expression. &nbsp;Modeling everything as throws in Swift would be super-annoying and unergonomic for the programmer,&nbsp;because we'd require 'try' everywhere. &nbsp;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="">&nbsp; &nbsp; let a = np.array([1, 2, 3])</font></div><div><font face="Menlo" class="">&nbsp; &nbsp; let b = np.array([[2], [4]])</font></div><div><font face="Menlo" class="">&nbsp; &nbsp; 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="">&nbsp; &nbsp; // 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`&lt;T&gt;(_ body: () throws -&gt; T) throws -&gt; 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&nbsp;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="">&nbsp; let dogClass = python_getClassByName(“Dog”) // implemented in the Python “overlay’, I guess</div><div class="">&nbsp; let dog = python_createInstance(dogClass) &nbsp;// implemented in the Python “overlay’, I guess</div><div class="">&nbsp; dog.__init__(“Brianna”) &nbsp; &nbsp; &nbsp;// uses CustomCallable’s callMember</div><div class="">&nbsp; dog.add_trick(“Roll over”) &nbsp;// 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 =&nbsp;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,&nbsp;</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>&nbsp; init(_ name: Pythonable)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>&nbsp; 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&nbsp;that every other dynamic language would get support hacked directly into Swift. &nbsp;The only reason I can see this being useful is if we&nbsp;wanted to support the optional typing annotations in Python. &nbsp;While this would be "nice to have", I think the cost/benefit tradeoff&nbsp;involved is totally wrong for Swift.&nbsp;</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>