> On Nov 11, 2017, at 10:15 AM, Joe Groff via swift-evolution
> <[email protected]> wrote:
>
>
>
> On Nov 11, 2017, at 10:04 AM, Chris Lattner <[email protected]
> <mailto:[email protected]>> wrote:
>
>>
>>
>>> On Nov 11, 2017, at 6:29 AM, Joe Groff via swift-evolution
>>> <[email protected] <mailto:[email protected]>> wrote:
>>>
>>>> below the fold as far as the rest of the language is concerned. You could
>>>> just as well written what the importer synths up in Swift directly:
>>>>
>>>> func foo(bar: String) {
>>>> unsafeBitCast(objc_msgSend, to: @convention(c) (AnyObject, Selector,
>>>> NSString) -> ().self)(self, "fooWithBar:", NSString(bar))
>>>> }
>>>>
>>>> and the rest of the language would be none the wiser.
>>>
>>> Though, since you bring up objc_msgSend, the way it works in ObjC might be
>>> a better fit for Swift's name lookup model, since their keyword argument
>>> models are similar. If Swift had a 'method of last resort' like ObjC's
>>
>> In fact, this is the subject of the next proposal that I will write up when
>> I have time.
>
> It seems to me like a dynamic method-of-last-resort feature would subsume
> this proposal. Out of curiosity, why would we need both?
It seems that you missed the "[Discussion] Swift for Data Science / ML / Big
Data analytics” thread, in which a lot of context was discussed, as well as
multiple design approaches. In any case, I will summarize here:
There are two fundamental operations that need to be supported to make a big
impact on dynamic language interop: member lookup and calls.
Many languages treat these as separable concepts. In Python for example, these
are equivalent:
return foo.bar(x: 1, 23, y: 17)
and:
a = foo.bar
return a(x: 1, 23, y: 17)
Swift and the other Smalltalk inspired languages are the odd ones out who tie
method arguments into the base name of a function. With no language changes,
it is possible to implement a pretty reasonable Python interop layer with the
call and member operations explicit, it looks like this:
func example(foo : PyVal) -> PyVal {
return foo.get(member: “bar”).call(args: (“x”, 1), (“”, 23), (“y”,
17))
}
and while it is totally possible to sugar common cases, e.g.:
func example(foo : PyVal) -> PyVal {
return foo.call(member: “bar”, args: (“x”, 1), (“”, 23), (“y”, 17))
}
you still need to support the basic model because Python supports currying and
has global functions with keyword arguments. FWIW, Perl follows a similar
model, but doesn’t have keyword arguments.
I don’t really care much about the implementation approach (if this proposal
isn’t the right one, fine!) but it is important to get this down to:
func example(foo : PyVal) -> PyVal {
return foo.bar(x: 1, 23, y: 17)
}
which I hope you’ll agree is a *HUGE* readability and writability benefit, so
much so that users would reject the long hand notion.
The discussion phase in the previous thread considered several approaches,
including burning python specific support in, implementing a python importer,
and implementing a single “dynamic thing” protocol. These are all bad ideas
for reasons described in the thread. If you’re curious, I’m happy to elaborate
in alternatives considered.
As such, discussion converged on pitching two proposals, which are generally
useful beyond this niche:
1. The dynamically callable one already written.
2. A dynamically member lookupable proposal to sugar things like
foo.get(member: “bar”) - and the corresponding setter.
The former one is presumably useful for things outside dynamic languages, e.g.
implementing dynamic “proxy” type interfaces.
The second one is useful for far more than just dynamic languages, e.g.
sugaring json keypath traversals.
-Chris
_______________________________________________
swift-evolution mailing list
[email protected]
https://lists.swift.org/mailman/listinfo/swift-evolution