I don't quite understand why we'd need a name that avoids any awkwardness, or that would need to be immediately understood by anyone not aware of the feature.
On the contrary, names that stand out make it easy to trigger strong mental tricks such as convention and googleability. Especially for "magic" features. They make any confusion disappear.
This probably came up in other threads but to be honest Iād prefer anonymous functions just like subscripts, as it would perfectly define the whole metal model for this feature. func (), func (param: Int) -> Int.
If we did that we could also opt in into named subscripts for cases were view types are not efficient enough.
/* static */ func #name#(#param_list#) #trailing_stuff#
// we could allow this:
/* static */ subscript #name#(#param_list#) #trailing_stuff#
// this proposal
/* static */ func (#param_list#) #trailing_stuff#
// existing symmetric part
/* static */ subscript (#param_list#) #trailing_stuff#
Since subscripts can be nameless, and do not require a leading dot during the call, the current proposal should just drop the function name entirely and also not require the dot (which it already does as proposed). All known rules from get only subscripts could be applied here as well.
It is not a noun. It is a verb phrase formed from a verb plus a direct object ā just like dropFirst, updateValue, reserveCapacity, formUnion, removeAll, and addSubview.
It is worth noting that in all those examples, the direct object (first, value, capacity, union, all, subview) refers to the first argument of the function. I agree with what Garth said: callFunction implies that the arguments are a function, not the receiver.
callAsFunction is a better name, and one I like.
This section of the API guidelines seems to apply here (note especially the red box):
All your examples for function are from (Objective-C) APIs, and not from Swift keywords or standard library APIs. I don't know how much of a difference that should make, if any. Your examples for int are obviously more relevant.
+1. Iām not a fan of the direction recommended by the core team. The approach of using unnamed methods feels a lot more elegant, a lot less magical, and doesnāt introduce a method we donāt really want to be directly accessible. Further, func () or func _ () is every bit as searchable as anything else we might come up with.
The only downside I can see to the unnamed method approach is that there isnāt a way to refer to the unapplied method as a function. This seems fine. There are future directions to address that. In the meantime writing { callableValue($0) } is not a big deal.
I donāt see why we should have to use a rather arbitrary and ungainly name callable methods. Setting aside the fact that subscripts canāt be methods for a moment, if they could would we really want to spell them func accessSubscript? I sure hope note.
"functionCall" would be consistent with "subscript", linguistically. If we really want "call" to act as a verb, there's "callAsFunction", but I don't find that to be an improvement
Since subscript is not to name anything while func is to name a function, I'm not a big fan of name less func unless it'll allow us to name a subscript as well.
func something() // what we have today.
subscript something() // NOT what we have today.
But I think that many folks agreed that subscript is the perfect mental model for this functionality. Therefore, introducing new keyword instead could work best, I thought.
call() // not sure why this was rejected.
subscript() // what we have today.
Now, while I can't tell if someone is willing to propose new subscript magic in the future, I feel it can make more sense to new users for symmetricity.
func callFunction() // what we'll have.
func subscriptFunction() // NOT what we have today.
I've updated the SE-0253 implementation to use callFunction instead of call as the call-syntax delegate method name. By the way, the implementation is currently ~150 LOC - not too big.
There's one remaining known bug where call-syntax sugar fails for mutating func callFunction and IUO. Advice on fixing this (handling mutating func callFunction more robustly) would be appreciated.
struct Mutating {
var x: Int
mutating func callFunction() {
x += 1
}
}
func testIUO(f: inout Mutating!) {
f() // not okay
f.callFunction() // okay
}
mutating_iuo.swift:8:3: error: cannot use mutating member on immutable value: 'f' is immutable
f() // not okay
^
+1. I think this is analogous to C++'s famously verbose template <typename T>. When we introduced these features, lots of people (including me) had this strange idea that people might "abuse" them; so we invented extra syntax to warn you that something strange and scary is coming.
But on reflection - these features are part of the language. We should just get over it, accept that they are here to stay and try to make them great. It's important to make things clear so you don't accidentally add support for these features when you didn't mean to; but beyond that, burdening them with extra syntax is so 1980s.
But now we have the problem of functions with magic names and special calling syntax. As I mentioned in the review, the language already has this problem because of operators, but in practice they tend to get away with it because they have a restricted character set which only allows "operatory-looking" things:
// Okay
infix operator |/
// Error: 'abc' is considered to be an identifier, not an operator
infix operator abc
I don't exactly love the name func callFunction(...); it feels kind of verbose and awkward. It almost reads like a command, as if it's saying "call a function", which doesn't really make much sense.
My preferred spellings are, in order:
func () (...args...)
func __call(...args...)
func callFunction(...args...)
Although I appreciate that #1 might be difficult for beginners to Google when they first encounter it. I'm not sure if that should be a massive concern. #2 doesn't have any precedent in the language, but it's shorter and clearer than #3, and possibly has even better Googlability.
I very much like @Joe_Groff's suggestion to borrow Python's **kwargs and to use it to absorb dynamicCallable in to this. It's a better conceptual model and enables lots of nice features. It's a much more Swifty way of doing variadic parameters.
If we go in that direction, it means we don't need to care so much about being consistent with func dynamicallyCall(args/kwArgs) because it will eventually be deprecated anyway.
Named subscripts are not purely about symmetricity, they would allow us to avoid creating view types and potentially provide some enhancements such as avoiding unnecessary copies (in a few cases), while keeping the name for convenient API usage. The gain is minimal but it would align well if this proposal would use unnamed methods.
The Core Team has no interest in using special syntax to declare these functions. Please confine your suggestions to ordinary identifiers. If there's no consensus on a better alternative to callFunction, we'll just stick with that.
Can you specify 'special syntax'? I think using callFunction is special syntax, but unnamed methods would have precedent in the language as they would align to read only subscripts for both the member definition and usage (except for the parameter label rules).
Right: specifically the core team wants an already-valid identifier as the well-known name that triggers this feature. The identifier should be a compound word to reduce the odds of accidental conflict and to improve googlability. This is the model that dynamicCallable and dynamicMemberLookup use as well (once the attribute is gone).
The rationale for this is that we want to keep the language simple and uniform, and don't want to introduce special syntactic forms. The entrypoint is func-like in every way, so if someone wants to explicitly use it (e.g. for partial application) then being able to name it is important.