[Accepted with Modification] SE-0253 - Callable values of user-defined nominal types

The second review of SE-0253 - Callable values of user-defined nominal types ran through May 13. Compared to the first round, the feedback was relatively light, mostly focused on the options of how to spell the callable member, more discussions of a @callable attribute, many ways to spell the call method, as well as the higher level purpose of this extension.

The core team discussed the various options, whether an attribute was important, the tradeoffs between various names. For example, the invoke is sort of a term of art in NSInvocation but SE-0216 / @dynamicCallable has standardized the terminology of "call" already in the Swift community. There are existing func call implementations (e.g. there could be a Phone.call() method), and subtly providing callable behavior with a short and common name like call could be seen as surprising. The core team felt that the attribute doesn't appear to pay for itself, and existing types don't need to have an attribute to be subscript-able.

After discussing these and many other points, the core team decided to accept the proposal, with the request to change func call() syntax to func callFunction() . The core team chose this direction because it retains the 'call' nomenclature established by SE-0216, but is a more verbose name that is less likely to already exist, or be accidentally used for an unrelated purpose.

Accordingly, SE-0251 is accepted with modification .

Thank you to Richard Wei and Dan Zheng for their contributions that improve the Swift programming language!


As part of this discussion, the Core Team also considered the behavior of the existing dynamic call (SE-0216) and dynamic member-lookup (SE-0195) features. These features both require an attribute on the original type declaration, preventing retroactive extension of a type to support these features. In both cases, the attribute was not included in the original proposal, but was added during the review out of concern for abuse. The Core Team has not asked for a similar attribute for static calls because it has changed its mind and no longer agrees with this concern; it does not align with Swift's general design principles to restrict features this way. We therefore invite a new proposal to remove these restrictions.

-Chris Lattner
Review Manager

14 Likes

Bikeshed alert...

Was it mentioned during this discussion that, in isolation, it's not at all clear whether "call" is intended to serve as an adjective or a verb in this context (the name callFunction)? It is in fact an adjective, which is an unusual and somewhat awkward parsing of "call".

I would speculate that most readers unfamiliar with the system would assume callFunction() to be a method that accepts a function as an argument, which the receiving entity is then intended to call. But that's wrong.

I think clarity might be aided by keeping "call" as a verb. If you want a longer name, how about callAsFunction()?

14 Likes

Another interesting future direction would be to make something like Python’s **kwargs feature available to all functions, so that any function can declare it can take a variadic list of keyword: argument pairs. That would mean that dynamic-callable no longer has to be a separate feature; this new callable feature would be able to supersede it (aside from backward compatibility).

13 Likes

How would that be different from the labeled variadics I pitched a while ago?

The Core Team wanted a name that (1) used "call" instead of some synonym (e.g. "invoke"), (2) wasn't just the bare word "call" (or anything else likely to be used separately), and (3) ideally fit naturally with the precedent of SE-0216. And we didn't like "staticallyCall", or anything else with "static" in it. If there's consensus on an alternative, I think we would be open to considering it.

2 Likes

Okay, if the gates are open for a naming discussion here…

If it's expected that the differences between these features will be even further erased at some point, then it would be much nicer if their names could be aligned. Having dynamicallyCall(…) for one and callFunction(…) as the other is going to be very hard for me to remember. Source compatibility restricts changes to the former, and it seems you basically ruled out staticallyCall(…) for the latter, but perhaps someone can think of a reasonable replacement adverb.

5 Likes

What about instanceCall? The idea being conveyed is that it makes an instance of the enclosing type callable. It's not quite a parallel to dynamicallyCall, but you've ruled out the only true parallel.

1 Like

Alternatively, callOnInstance() is more verbose and doesn't match dynamicallyCall but is in my opinion clearer.

But you don't call the function on the instance, you "call" the instance using the function.

1 Like

Fair point – then just callInstance()?

I am cognizant of the fact that I may just be reflexively defending my own position in a subjective manner, but callInstance() doesn't sound quite right to me. It sounds more like the name of a property, or like you are referring to a variable named call (look at the call instance...). It also misses the parallelism to the dynamic version of the feature.

1 Like

Moreover, if such function can be defined as class or static, having instance in the name may be confusing.

2 Likes

As a user, call for me is as clear, rememberable and precise as subscript, guard, let etc. Sorry but callFunction, callInstance or staticallyCall are not that cool. Thanks.

8 Likes

Strong −1

The callFunction() API:

  • unnecessarily repeats type information (see Swift API Guidelines)
  • is a noun for no good reason (not particularly good OOP)
  • is inconsistent with established terminology (func vs Function)
  • is unnecessarily verbose (see Swift API Guidelines)
  • is inconsistent with Dynamic Callable API
  • is unnecessarily magical

When this was previously discussed, everyone had their own pet peeve. The funny thing is that with this modification, the API will (probably) disappoint everyone because it is inconsistent, magical, verbose, etc. All at once.

ducks

17 Likes

Maybe func callable?

6 Likes

Well, if everyone is disappointed equally, that's the best decision we can get for a controversial question ;-)

I'm also really not convinced by the explanation for the chosen name - but it's chosen now isn't it? In this case, discussion is over, and the only thing we can achieve here is a better understanding why the arguments for alternatives have been considered too weak by the Core team.

I thought of that, but I still don't have a better alternative. My story is that it would refer to an instance of the meta type, but I admit that it's a weak story.

The name is not yet set in stone, but the magical nature is.

+1 to func callable(). func callFunction() seems very awkward.

1 Like

-1 to function names containing "callable". All functions are already callable. I find it confusing to introduce a notion of "callable function".

7 Likes