[swift-evolution] [Pitch] Introduce user-defined dynamically "callable" types

Chris Lattner sabre at nondot.org
Fri Nov 10 23:53:01 CST 2017


> On Nov 10, 2017, at 9:10 PM, Brent Royal-Gordon <brent at architechies.com> wrote:
> Leaving the "should we do it at all" question aside…

Thanks, most of the comments in this thread haven’t been constructive at all, I’m glad to get one that is :-)

>> On Nov 10, 2017, at 9:37 AM, Chris Lattner via swift-evolution <swift-evolution at swift.org> wrote:
>> 
>> We propose introducing this protocol to the standard library:
>> 
>> protocol DynamicCallable {
>>  associatedtype DynamicCallableArgument
>>  associatedtype DynamicCallableResult
>> 
>>  func dynamicCall(arguments: [(String, DynamicCallableArgument)]) throws -> DynamicCallableResult
>> }
>> 
>> It also extends the language such that function call syntax - when applied to a value of DynamicCallable type - is accepted and transformed into a call to the dynamicCall member. The dynamicCall method takes a list of tuples: the first element is the keyword label (or an empty string if absent) and the second value is the formal parameter specified at the call site.
> 
> I don't really like passing the argument names to the parameter list. Instead, I would prefer to see them handled in the member-resolution method. You don't give a design for DynamicMemberLookupProtocol here, but assuming that you're imagining that a call like this:
> 
> 	foreignObject.someValue(keyword1: 42, "foo", keyword2: 19)
> 
> Would translate to something like this:
> 
> 	foreignObject.dynamicMethodLookup(name: "someValue").dynamicCall(arguments: [("keyword1", 42), ("", "foo"), ("keyword2", 19)])

Right, that was the idea.

> I would instead like it to look like this:
> 
> 	foreignObject.dynamicMethodLookup(name: "someValue", arguments: ["keyword1", "", "keyword2"]).dynamicCall(arguments: [42, "foo", 19])
> 
> This would better suit languages like Squeak (or Swift!) where you cannot fully look up a method without its keywords.

Good point.

> (Languages like Python would simply store the keywords inside the object returned by `dynamicMethodLookup`.)

While I don’t care greatly about making Python efficient, doing this storage would be grossly inefficient and doesn’t have an obvious implementation.  Python also supports currying, and global functions with keyword arguments, which means that:

	fn(keyword1: 42, "foo", keyword2: 19)

… needs to work, even if x didn’t come from Swift.

I guess we can solve both use cases by passing the keyword in both cases for a Swift style call.  Your example would look like this:

foreignObject.dynamicMethodLookup(name: "someValue", arguments: ["keyword1", "", "keyword2"]).dynamicCall(arguments: [(“keyword1”, 42), (“”, “foo"), (“keyword2”: 19)])

The fn example above would look like this:

	fn.dynamicCall(arguments: [(“keyword1”, 42), (“”, “foo"), (“keyword2”: 19)]

And a member lookup with no call would simply pass no arguments.

> It would also allow you to use our "get-a-closure" syntax:
> 
> 	let uncalledMethod = foreignObject.someValue(keyword1:_:keyword2:)

Yep, that would pass the keywords to member lookup.  They’d be ignored by Python but presumably used for Squeak.

-Chris



More information about the swift-evolution mailing list