> 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

Reply via email to