<div dir="ltr">On Sun, Dec 3, 2017 at 2:20 PM, Karl Wagner via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div><blockquote type="cite"><div style="word-wrap:break-word;line-break:after-white-space"><div><div><br></div><div>I believe that adding explicit syntax would be counterproductive to your goals, and would not make dynamic lookup syntax more clear. I assume that you would also want the same thing for DynamicCallable too, and operator overloads, subscripts, and every other operation you perform on these values, since they all have the exact same behavior.</div><div><br></div><div>If we required some syntax even as minimal as “foo.^bar” and "baz^(42)”, that change would turn this (which uses runtime failing or IUO return values like AnyObject):</div><div><br></div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let np = Python.import("numpy")<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let x = np.array([6, 7, 8])</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let y = np.arange(24).reshape(2, 3, 4)</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span></div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let a = np.ones(3, dtype: np.<wbr>int32)</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let b = np.linspace(0, pi, 3)</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let c = a+b</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let d = np.exp(c)</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>print(d)</div><div><br></div><div>into:</div><div><br></div><div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let np = Python.import("numpy")<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let b = np^.array^([6, 7, 8])</div><div><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let y = np^.arange^(24)^.reshape^(2, 3, 4)<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span><br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let a = np^.ones^(3, dtype: np^.int32)<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let b = np^.linspace^(0, pi, 3)<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let c = a+^b<br><span class="m_8876656564668904248Apple-tab-span" style="white-space:pre-wrap">        </span>let d = np^.exp^(c)</div><div><br></div></div><div>This does not improve clarity of code, it merely serves to obfuscate logic. It is immediately apparent from the APIs being used, the API style, and the static types (in Xcode or through static declarations) that this is all Python stuff. When you start mixing in use of native Swift types like dictionaries (something we want to encourage because they are typed!) you end up with an inconsistent mismash where people would just try adding syntax or applying fixits continuously until the code builds.</div></div></div></blockquote><br></div><div>That’s not Swift. You just wrote a bunch of Python. For example, Swift has a native Int32.+ operator which fails on overflow - does your example also do that? Anybody’s guess! Does your numpy array conform to Collection? I guess not, because it’s an opaque Python value.</div><div><br></div><div>That’s exactly the kind of stuff I, as a user of the language, really don't want to see mixed together with real Swift. I appreciate the need to use functionality from libraries written in Python, but I don’t appreciate it being so invisible and pervasive throughout the language. If you have a bunch of Python logic, I’d prefer you wrote as much of it as possible in Python, with as few bridging points to Swift as you can get away with. I remain convinced that this design encourages the opposite - because, as you said earlier, it’s “too good”.</div></div></blockquote><div><br></div><div>The use case that Chris is solving here is precisely how to enable the writing of this type of code in Swift. Put another way, how do I interface with libraries written in Python without writing my own code in Python? "That's exactly the kind of stuff I really don't want to see mixed together with real Swift" and "I'd prefer you wrote as much of it as possible in Python" is not an answer; it's rejecting the legitimacy of the use case in the first place.</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div>As for the point about Swift already including non-marked, potentially-crashing operations (like the + operator, or Array subscripting): nobody likes that behaviour!</div></div></blockquote><div><br></div><div>I, for one, very much like that behavior. Swift has many non-marked, potentially-crashing operations because that is both performant and safe. There is a common misconception that crashing is unsafe, with corresponding misconceptions such as avoiding "!". This is simply incorrect.</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word;line-break:after-white-space"><div>Whenever I come to a new Swift codebase, I almost universally find that people have written their own “safe” Array accessor which integrates bounds-checking and returns an Optional. The issue has come up here many, many times for inclusion in the standard library. I certainly would not use it as justification for adding more of those kinds of unmarked, potentially-unsafe operations. Also, enough Swift developers know about the Array subscript behaviour that the square brackets almost become a marker, like “!”, of a potentially-failing operation. The same is not true of the dot operator, in general.</div><div><br></div><div>I also don’t agree with the comparisons to Objective-C/AnyObject dispatch. It’s true that it’s unsafe to an extent, but it’s also orders of magnitude safer than this sort of dispatch. Clang is integrated in to the compiler, and can at least perform some rudimentary checking of method signatures/selectors. This sort of dispatch provides absolutely no protections whatsoever — is “arange” really a function? Is it not really a typo for “arrange”? That’s something I need to Google. With regular Swift I can assume that if the compiler allows it, there is a function called “arange” somewhere, and all I need to worry about is whether the erased AnyObject is of the correct type to respond to that message. And as I said earlier, AnyObject is incredibly rare in practice anyway. So no, I don’t agree that we should just keep lowering the safeguards; it’s like demolishing your house because of one draughty door.</div><div><br></div><div>What I <i>could</i> support, would be some kind of optional syntax, possibly with some kind of associated scope which allows you omit it. Something like:</div><div><br></div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><font face="Courier">// Normally, optionals are required.</font></div><div><font face="Courier">let result: PythonObject? = pythonObj.someProperty?.<wbr>someFunction(1, 2, 3)</font></div><div><font face="Courier"><br></font></div><div><font face="Courier">// Within a special scope, you can omit them. The scope will bail at the first lookup failure and return nil.</font></div><div><font face="Courier">let result: PythonObject? = Python {</font></div><div><font face="Courier"> return pythonObj.someProperty.<wbr>someFunction(1, 2, 3)</font></div><div><font face="Courier">}</font></div><div><font face="Courier"><br></font></div></blockquote>Perhaps the “Python” object could conform to a protocol with an associated type for the objects it can implicitly unwrap. There would be some additional compiler work, for sure, but that’s secondary to a good language model IMO (easy for me to say, I know).<div><blockquote style="margin:0 0 0 40px;border:none;padding:0px"><div><br></div></blockquote><div><br></div><div>- Karl</div></div></div><br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/<wbr>mailman/listinfo/swift-<wbr>evolution</a><br>
<br></blockquote></div><br></div></div>