<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=""><div><br class=""><blockquote type="cite" class=""><div class="">On Nov 1, 2017, at 03:14, Richard Wei via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class="Apple-interchange-newline"><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 class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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 class=""><br class=""></div><div class="">I agree, PythonObject-or-die is the right trade-off.</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class=""><font face="Menlo" class="">try Python.do {</font></div><div class=""><font face="Menlo" class=""> let a = np.array([1, 2, 3])</font></div><div class=""><font face="Menlo" class=""> let b = np.array([[2], [4]])</font></div><div class=""><font face="Menlo" class=""> print(a.dot(b)) // matrix mul with incompatible shapes</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch let error as PythonException {</font></div><div class=""><font face="Menlo" class=""> // Handle PythonError.valueError(“objects are not aligned”)</font></div><div class=""><font face="Menlo" class="">}</font></div></div></div></blockquote><div><br class=""></div><div>To correct my example: </div><div><br class=""></div><div><div class=""><font face="Menlo" class="">do { </font></div><div class=""><font face="Menlo" class=""> try Python.do {</font></div><div class=""><font face="Menlo" class=""> let a = np.array([1, 2, 3])</font></div><div class=""><font face="Menlo" class=""> let b = np.array([[2], [4]])</font></div><div class=""><font face="Menlo" class=""> print(a.dot(b)) // matrix mul with incompatible shapes</font></div><div class=""><font face="Menlo" class=""> }</font></div><div class=""><font face="Menlo" class="">}</font></div><div class=""><font face="Menlo" class="">catch let error as PythonException {</font></div><div class=""><font face="Menlo" class=""> // Handle PythonError.valueError(“objects are not aligned”)</font></div><div class=""><font face="Menlo" class="">}</font></div></div><div><br class=""></div><div>Maybe ‘Python.do {}’ should be called something like ‘Python.safely {}’.</div><div><br class=""></div><div>-Richard</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""></div><div class="">Python.do enables exception handling for statements in the body, declared as</div><div class=""><font face="Menlo" class="">func `do`<T>(_ body: () throws -> T) throws -> T</font></div><div class=""><br class=""></div><div class="">When we execute python-throwing statements inside a Python.do{}, PythonException gets thrown. Otherwise, it traps.</div><div class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">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 class=""><br class=""></div><div class="">-Richard</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class=""><br class=""></div><div class=""><pre class="" 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);"><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 class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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 class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;"><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">_______________________________________________</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><span style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px; float: none; display: inline !important;" class="">swift-evolution mailing list</span><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="mailto:swift-evolution@swift.org" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">swift-evolution@swift.org</a><br style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></body></html>