SE-0253: Static callables

Thanks for your feedback, @anandabits and @Joe_Groff.
I'm sorry, point "2)" from me was uninformed. "Special function constraint kinds" sounds quite more sensible.

This answer is flippant and not at all convincing. Dynamic callables and dynamic member lookup are also first-class features.

That said, func _ isn’t a great alternative either. It doesn’t feel Swifty and isn’t a very natural way to reuse _. Both func call and @<someattr> func whatever feel more consistent with other type system special cases.

Taking a completely different approach to dynamic callables doesn’t mesh well with this goal.

1 Like

I feel your response is a bit strong. Dynamic callables (call-syntax sugar with special handling of argument labels) are a niche feature, and thus have niche syntax. Callables (call-syntax sugar) are less niche and deserve more first-class syntax.

Example from Scala:

I think dynamic callables and callables are orthogonal language features and making them mesh well is a non-goal. Making them share a mechanism for declaring call-syntax delegate methods is also not necessarily a goal.

3 Likes

Love @implicit, this is exactly what a call is here and should be applicable to any function.

2 Likes

The meaning of "implicit" is too broad for this feature. Function declarations marked with implicit may also connote orthogonal features in other languages. For instance, an implicit function in Scala may define an implicit conversion.

5 Likes

I don't support that narrow definition - for one thing, ternary operators exist and we even have one in Swift! We don't support user-defined ternary operators or allow custom implementations, but in theory there's no reason why we couldn't if there were some compelling use-cases.

but, I agree with the general argument: operators have a slightly different syntax at the point of use, but otherwise they are just ordinary functions. They are just sugar.

  • When calling, I can write, say, 1 + 2 instead of Int.+(1, 2), and
  • When referring to the operator's implementation (as in myInts.reduce(0, +)), I don't need to prefix the member name with a dot (myInts.reduce(0, .+))

And when you read this proposal, the same thing sticks out: myPoly(42) is just sugar around calling a specially-named function member: myPoly.evaluate(42) - or, spelled in more of an operator-y way: Polynomial.evaluate(myPoly, 42) (see my point above about how it's curious that we require operator implementations to be static).

So yes, static callables do not exactly fit within the very narrow range of stdlib-defined operators that we have today, but I think we only need to massage the edges a little bit, and that small expansion would be quite useful generally. The whole idea that there can be operators with an implementation-defined number of parameters with implementation-defined types and where argument labels are preserved is a powerful abstraction that could also help us solve problems like the unspellable requirements in the string-interpolation redesign.

P.S: As for subscripts: there is a reasonable argument that they also should be operators, but that would require an even larger expansion of the operator model.

2 Likes

This proposal was returned for revision by the core team.

Thank you to everyone who participated.

Chris Lattner
Review Manager

2 Likes