<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=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class="">[Arg, I keep sending these with the wrong from address and getting bounced! Excited for Discourse…]</div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div class=""><br class=""><blockquote type="cite" class=""><div class="">On Nov 16, 2017, at 12:00 AM, Brent Royal-Gordon via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html; charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 14, 2017, at 11:29 PM, Chris Lattner via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="highlight highlight-source-swift" style="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-size-adjust: auto; -webkit-text-stroke-width: 0px; box-sizing: border-box; margin-bottom: 16px; color: rgb(36, 41, 46); font-family: -apple-system, system-ui, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;, &quot;Segoe UI Symbol&quot;; font-size: 16px; font-variant-ligatures: normal; orphans: 2; widows: 2;"><pre class="" style="box-sizing: border-box; font-family: SFMono-Regular, Consolas, &quot;Liberation Mono&quot;, Menlo, Courier, monospace; font-size: 13.6px; margin-top: 0px; margin-bottom: 0px; word-wrap: normal; padding: 16px; overflow: auto; line-height: 1.45; background-color: rgb(246, 248, 250); border-top-left-radius: 3px; border-top-right-radius: 3px; border-bottom-right-radius: 3px; border-bottom-left-radius: 3px; word-break: normal;"><span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">extension</span> <span class="pl-en" style="box-sizing: border-box; color: rgb(111, 66, 193);">PyVal</span> {
  <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">subscript</span>(dynamicMember member<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">:</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">String</span>) <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">-&gt;</span> PyVal {
    <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">get</span> {
      <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">let</span> result <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">=</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">PyObject_GetAttrString</span>(borrowedPyObject, member)<span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">!</span>
      <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">return</span> <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">PyRef</span>(<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">owned</span>: result)  <span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"><span class="pl-c" style="box-sizing: border-box;">//</span> PyObject_GetAttrString returns +1 result.</span>
<span class="pl-c" style="box-sizing: border-box; color: rgb(106, 115, 125);"></span>    }
    <span class="pl-k" style="box-sizing: border-box; color: rgb(215, 58, 73);">set</span> {
      <span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">PyObject_SetAttrString</span>(borrowedPyObject, member,
                             newValue.<span class="pl-c1" style="box-sizing: border-box; color: rgb(0, 92, 197);">toPython</span>().<span class="pl-smi" style="box-sizing: border-box;">borrowedPyObject</span>)
    }
  }
}</pre></div></div></blockquote></div><div class="">This looks great for Python, but let's talk about some other languages for a moment.</div><div class=""><br class=""></div><div class="">* Ruby and Perl don't have the "call a method by fetching a closure property and invoking it" behavior you're relying on here. Instead, Ruby has a syntax for settable "overloads" of methods (i.e. you can write `def someMember` and `def someMember= (newValue)`), while Perl supports lvalue methods (but sometimes uses getter and setter method pairs instead). How do you envision these behaviors being bridged to Swift? I worry that this protocol may not be sufficient, and that we may need a design which can distinguish between looking up methods and looking up properties.</div></div></div></blockquote><div class=""><br class=""></div><div class="">I’ve never pried the lid of Ruby’s implementation of method dispatch, but I’m pretty sure that if foo defines a bar method, then</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; foo.bar(…args…)</div><div class=""><br class=""></div><div class="">is fully equivalent to:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; foo.method(:bar).call(…args…)</div><div class=""><br class=""></div><div class="">IOW, there is an intermediate Method object that would fit the shape of the proposed callable protocol.</div><div class=""><br class=""></div><div class="">If foo instead doesn’t actually declare the bar method, but instead handles it via method_missing or __send__, then foo.method(:bar) raises an exception. However, it would be trivial to write a deferred invocation wrapper that also fits the shape of the proposed protocols and calls foo.send(“bar”, …args…) at the appropriate time.</div><div class=""><br class=""></div><div class="">In short, I don’t think there’s a problem here.</div><div class=""><br class=""></div><div class="">In the example you bring up:</div><div class=""><br class=""></div><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><div class="">you can write `def someMember` and `def someMember= (newValue)`)</div></div></blockquote><br class=""></div><div class="">…there is no overloading. The = is _part of the method name_, i.e. there is a `someMember` method and a `someMember=` method. The following are equivalent:</div><div class=""><br class=""></div>&nbsp; &nbsp;&nbsp;foo.bar = 3 &nbsp;# just sugar</div><div class="">&nbsp; &nbsp; foo.bar=(3)<br class=""><div class="">&nbsp; &nbsp; foo.send("bar=", 3)</div><div class=""><br class=""></div><div class="">Ruby allows ?, !, and = as the last char of method names, and AFAIK other than the special sugar around setters, they are just parts of the method name with no further semantic significance.</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="">* Ruby looks up members using symbols, which essentially play the same role as selectors in Objective-C—they're uniqued strings which are used for fast member dispatch. In some cases, you might see non-negligible speed improvements by only looking up the symbol once. Is there a way this design could accommodate that? For instance, could the type of the index be specified by an associated type, so Ruby could use a RbSymbol instead of a String? Or do you think that would be overkill?</div></div></blockquote><div class=""><br class=""></div><div class="">Good question. The language gets its symbol speedup by canonicalizing symbols at compile time when possible, and that failing, when symbolicated instead of when dispatched:</div><div class=""><br class=""></div><div class=""><div class="">&nbsp; &nbsp; one_zillion.times { foo.some_long_method_name } &nbsp;# fastest</div></div><div class=""><br class=""></div><div class=""><div class="">&nbsp; &nbsp; # only ~1.5x slower than prev, despite one extra method dispatch:</div><div class="">&nbsp; &nbsp; one_zillion.times { foo.send(:some_long_method_name) }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; # performance identical to previous:</div><div class="">&nbsp; &nbsp;&nbsp;symbol = string.to_sym</div><div class="">&nbsp; &nbsp; one_zillion.times { foo.send(symbol) }</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; # ~2x slower:</div><div class="">&nbsp;&nbsp; &nbsp;one_zillion.times { foo.send(string) }</div></div><div class=""><br class=""></div><div class="">(Those are based on actual benchmarks.)</div><div class=""><br class=""></div><div class="">Swift should be able to do the same optimizations. Making the method name a string would preclude that.</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=""><br class=""></div><div class="">* Generally, you've talked about properties (in this proposal) and methods (in the `DynamicCallable` proposal), but what about subscripts? Obviously you can just specify a `subscript(Pythonable) -&gt; PyVal` on `PyVal` for the simple case, but what if the subscript takes multiple indices or has labels? Do we need a `DynamicSubscriptable` protocol?</div><div class=""><br class=""></div><div class="">* Let's step away from bridging entirely and just think about Swift for a moment. There are cases where we'd like to make *semi*-dynamic proxies which wrap another type and allow operations based on what's statically known about that type. Think, for example, of the appearance proxy in UIKit: This is an object attached to UIView subclasses which lets you (in essence) set default values for all instances. We currently just pretend it's an instance of `Self`, which mostly works because of Objective-C, but a Swift-native version would probably prefer to return a `UIAppearance&lt;Self&gt;` object which used its knowledge of `Self` to expose `Self`'s properties on itself. Is there a way we could design this feature, or a related feature, to cover that kind of use case? That is, to allow a limited set of keys—perhaps even key-path-based when you want static control—with a different type for each key, *or* to allow any key with some common type, depending on your type's needs?</div></div></blockquote><div class=""><br class=""></div><div class="">Per my question about whether native methods shadow dynamic ones, one might be able to achieve some of this using a mix of statically typed, statically declared methods + dynamic members.</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=""><br class=""></div><div class="">* Actually, for that matter, let's talk about key paths. In principle, you can already think of member lookup in Swift—or at least property and subscript lookup—as though it always worked by constructing a key path and using `subscript(keyPath:)` to access it. Is there some way we could model this feature as extending the set of keys available on a given type—perhaps in a way that allowed compile-time-limited and strongly-typed sets of keys, like I mention with the `UIAppearance` example, in addition to the open-ended, type-erased sets you need—and then looking things up by key path? (Sorry if this is a little vague—I know very little about how key paths are implemented.)</div><div class=""><br class=""></div><div class="">* An implementation-level question about Swift: Internally, the compiler seems to be moving towards thinking of parameter labels as part of the identifier, rather than having them label the individual arguments. How do you see that jibing with what you're proposing here?</div><div class=""><br class=""></div><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">--&nbsp;</div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>

</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=""></blockquote></div><br class=""></div></body></html>