<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 dir="auto" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Nov 16, 2017, at 1:44 PM, Paul Cantrell <<a href="mailto:paul@bustoutsolutions.com" class="">paul@bustoutsolutions.com</a>> wrote:</div><br class="Apple-interchange-newline"><div class=""><div class=""><blockquote type="cite" class=""><div class="">On Nov 16, 2017, at 12:00 AM, Brent Royal-Gordon 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 class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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=""> foo.bar(…args…)</div><div class=""><br class=""></div><div class="">is fully equivalent to:</div><div class=""><br class=""></div><div class=""> 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=""></div></div></div></blockquote><div><br class=""></div><div>True. Ruby doesn't dispatch everything through a Method object…but I guess Swift sort of does, and we're bridging semantics into Swift here.</div><br class=""><blockquote type="cite" class=""><div class=""><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.</div></div></blockquote><div><br class=""></div><div><div>You're right—I was speaking imprecisely when I used the word "overloading". Nevertheless, Ruby doesn't quite directly interpret `x.someMember = y` as `x.someMember= (y)`—it supports operators like `+=`, which do a getter-operation-setter dance.</div></div><br class=""><blockquote type="cite" class=""><div class=""><div class="">The following are equivalent:</div><div class=""><br class=""></div> foo.bar = 3 # just sugar</div><div class=""> foo.bar=(3)<br class=""><div class=""> 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></div></blockquote><div><br class=""></div><div>You're correct that, with this design, you could access Ruby accessors from Swift with syntax like:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>myObj.name()</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>myObj.`name=`("Chris")<span class="Apple-tab-span" style="white-space: pre;">                </span>// If we loosened the characters allowed in backticks</div><div><br class=""></div><div>My point is simply that this is a poor mapping, for much the same reason `dog["add_trick"].call(…)` is a poor mapping. It's technically correct and exposes the functionality, but it's awkward and doesn't match the user's mental model.</div><div><br class=""></div><div>If we had separate subscripts for methods and properties, then the property subscript could immediately call the appropriate getters and setters, while the method subscript could return a ready-to-call `Method` object. This would prevent you from fetching uncalled methods using the `x.method` syntax (as opposed to `x.method(_:)`, which could be made to work), but that seems a lot better than a mapping that's technically correct but breaks the mental model.</div><br class=""><blockquote type="cite" class=""><div class=""><blockquote type="cite" class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;"><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<Self>` 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></div></blockquote><br class=""></div><div>So, let me sketch a vague idea of how this might work. This is definitely not fully baked, but it might give you an idea.</div><div><br class=""></div><div>Imagine you want to write an ORM. Its root class, `Record`, should expose a property for each field in a given record. You could make the ORM generate an enum like this:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>enum PersonProperty: String {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>case id, name, birthDate, address</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>And then make `Record` dynamically gain a property for each enum case by defining the `subscript(additionalProperty:)` subscript:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>class Record<Property> where Property: RawRepresentable, Property.RawValue == String {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript(additionalProperty property: Property) -> Any {</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>get { … }</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>set { … }</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>Swift will notice this overload and essentially augment `Record<T>` with a property for each case of `T`, giving it type `Any`. Attempting to use any of these properties will pass through this subscript. (Presumably, if you generated the key path `\Record<PersonProperty>.name`, you'd actually end up with the key path for `\Record<PersonProperty>.[additionalProperty: PersonProperty.name]`.)</div><div><br class=""></div><div>With a more sophisticated (and convoluted) design, our ORM could give the fields more specific types than `Any`:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>struct Property<RecordType: Record, Value> {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>let name: String</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Property where RecordType == Person, Value == Int {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>static let id = Property(name: "id")</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Property where RecordType == Person, Value == String {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>static let name = Property(name: "name")</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>static let address = Property(name: "address")</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Property where RecordType == Person, Value == Date {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>static let birthDate = Property(name: "birthDate")</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>And we could then expose typed, automatically created properties:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>protocol Record {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Record {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript<T>(additionalProperty property: Property<Self, T>) -> T {</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>get { … }</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>set { … }</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>struct Person: Record {}</div><div><div><div><br class=""></div><div><div>That would work for arbitrary fixed sets of properties, but we can extend this to wrapper types. Imagine you want to write the `UIAppearance` class I mentioned previously. (Actually, we'll call it `UIAppearanceProxy` to avoid names already used in UIKit.) Your basic structure looks like this:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>class UIAppearanceProxy<View: UIAppearance> {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>let containers: [UIAppearanceContainer.Type]</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>let traits: UITraitCollection</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>var properties: [PartialKeyPath<View>: Any] = [:]</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>Now, to make all properties of the `View` class settable on this class, you can overload the `additionalProperty` subscript to accept `View` keypaths:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension UIAppearanceProxy {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript<T>(additionalProperty viewKeyPath: KeyPath<View, T>) -> T? {</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>get {</div><div><span class="Apple-tab-span" style="white-space: pre;">                                </span>return properties[viewKeyPath] as! T?</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>set {</div><div><span class="Apple-tab-span" style="white-space: pre;">                                </span>properties[viewKeyPath] = newValue</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div><br class=""></div><div>Swift would notice this overload and allow any `View` property to be set on `UIAppearanceProxy`. The subscript gives its return type as `T?`, so when it does so, it will add an extra level of optionality—since `UITextField.font` is of type `UIFont?`, `UIAppearanceProxy<UITextField>.font` will be of type `UIFont??`. You can modify types like that in any way the type system permits.</div><div class=""><br class=""></div></div><div>For the totally dynamic use case, like Python, you could overload `subscript(additionalProperty:)` to take a `String` (or any other `ExpressibleByStringLiteral` type, like a `RubySymbol`):</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>extension PyVal {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript(additionalProperty member: String) -> PyVal {</div><div><span class="Apple-tab-span" style="white-space: pre;">                        </span>get {</div><div><span class="Apple-tab-span" style="white-space: pre;">                                </span>let result = PyObject_GetAttrString(borrowedPyObject, member)!</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                                </span>return PyRef(owned: result) // PyObject_GetAttrString returns +1 result.</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>set {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                                </span>PyObject_SetAttrString(borrowedPyObject, member, </div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                                        </span>newValue.toPython().borrowedPyObject)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Swift would map any completely unknown property to this key path, if present. <br class=""><br class="Apple-interchange-newline">* * *</div><div class=""><br class=""></div><div class="">Methods, I think, could be handled analogously. If you wanted a fixed but arbitrary set of automatically-"generated" methods, you might say something like:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>enum PersonMethod: Method {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>case insertJob(Job.Type, at: Int.Type)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>case removeJob(at: Int.Type)</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func implementation<P>(for record: Record<P, Self>) -> (Any...) -> Any { … }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>class Record<PropertyType: Property, MethodType: Method> … {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript (additionalMethod method: MethodType) -> (Any...) -> Any {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>get { return method.implementation(for: self) }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Swift will notice this overload and essentially augment `Record`'s methods with ones corresponding to the static methods of `MemberType`, so long as all of their parameters are metatypes. Attempting to use any of these methods will pass through this subscript. So `myPerson.insertJob(myJob, at: 0)` gets compiled into `myPerson[additionalMethods: PersonMethod.insertJob(Job.self, at: Int.self)](myJob, 0)`.</div><div class=""><br class=""></div><div class="">If you wanted stronger typing, you could do something like this:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>struct Method<RecordType: Record, ParameterTypes, ReturnType>: Method {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>enum Behavior {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>case insert</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>case remove</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>let field: String</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>let behavior: Behavior</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func implementation(for record: RecordType) -> (ParameterTypes) -> ReturnType { … }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension PersonMethod where RecordType == Person, ParameterTypes == (Job.Type, Int.Type), ReturnType == Job {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>static func insertJob(Job.Type, at _: Int.Type) -> PersonMethod {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return PersonMethod(field: "job", behavior: .insert)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension PersonMethod where RecordType == Person, ParameterTypes == (Int.Type), ReturnType == Void {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>static func removeJob(at _: Int.Type) -> PersonMethod {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return PersonMethod(field: "job", behavior: .remove)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>protocol Record {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension Record {</div><div class=""><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript <ParameterTypes, ReturnType>(additionalMethod method: Method<Self, ParameterTypes, ReturnType>) -> (ParameterTypes) -> ReturnType {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>get { return method.implementation(for: self) }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">(This would require that `subscript(additionalMethod:)` be allowed to pack parameter types into a single tuple, unless we were willing to wait for variadic generics.)</div><div class=""><br class=""></div><div class="">We could perhaps add a special case for wrapping methods which would leverage the unbound methods on a type (or whatever future replacement for that feature we devise):</div><div class=""><br class=""></div><div class=""><div><span class="Apple-tab-span" style="white-space: pre;">        </span>class UIAppearanceProxy<View: UIAppearance> {</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>let containers: [UIAppearanceContainer.Type]</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>let traits: UITraitCollection</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>var properties: [PartialKeyPath<View>: Any] = [:]</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>var calls: [(View) -> Void]</div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div></div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension UIAppearanceProxy {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript <ParameterTypes, ReturnType>(additionalMethod method: (View) -> (ParameterTypes) -> ReturnType) -> (ParameterTypes) -> Void {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return { params in</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                                </span>self.calls.append({ view in _ = method(view)(params) })</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">Note that here, we're completely changing the type of the method we return! Since we're deferring the call until later, we throw away the original return type and substitute `Void` instead. When you try to pull similar tricks in Objective-C (for instance, with `-[NSUndoManager prepareWithInvocationTarget:]`), you end up with invalid return values.</div><div class=""><br class=""></div><div class="">And of course, for Python and the like, you can use `ExpressibleByStringLiteral` types:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>extension PyVal {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>subscript (additionalMethod member: String) -> (PythonConvertible...) -> PyVal {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>let (baseName, labels) = splitMethodName(member)</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>// Python has a unified namespace for methods and properties, so we'll just leverage the property lookup.</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>let method = self[additionalProperty: baseName]</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return { arguments in method.dynamicCall(arguments: zip(labels, arguments)) }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>private func splitMethodName(_ name: String) -> (baseName: Substring, labels: [Substring]) {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>guard let argListIndex = name.index(of: "(") else {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                                </span>return (name, [])</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>let argListSansParens = name[argListIndex...].dropFirst().dropLast()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return (name[...argListIndex], argListSansParens.split(separator: ":")</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><br class=""></div><div class="">For types using both mechanisms, `subscript(additionalMethod:)` would be called whenever there was some sign—like a parameter list (with or without arguments) or an assignment to a function type—that we were looking up a method; `subscript(additionalProperty:)` would be called when there was no such sign. Python doesn't really need the two cases to be split up, but this would help a Ruby bridge differentiate between property and method accesses, and I think it would help with the more static cases as well.</div><div class=""><br class=""></div><div class="">* * *</div><div class=""><br class=""></div><div class="">This is a complex design, but I really like how much ground it covers. Python bridging is just the beginning—it can cover a *ton* of use cases with only a couple of variations. By not using protocols, it permits overloading and the use of generics tricks that might not be accessible to a protocol. </div><div class=""><br class=""></div><div class="">To begin with, we could support only `subscript(additionalProperty: String)` and `subscript(additionalMethod: String)`, and then expand over time to cover the more static use cases. That would get </div><div class=""><br class=""></div></div></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><div class="">Brent Royal-Gordon</div><div class="">Architechies</div><div class=""><br class=""></div></span></div></div></div></body></html>