You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Note: throughout this document, let "call-syntax" refer to the syntax of applying a function to arguments: `f(x, y, z)`.
12
12
13
13
This proposal introduces [callables](https://en.wikipedia.org/wiki/Callable_object) to Swift. Callables are values that define function-like behavior and can be applied using function application syntax.
14
14
15
-
In a nutshell, we propose to introduce a new declaration syntax with the keyword `call`:
15
+
In a nutshell, we propose to introduce a new declaration syntax with the keyword `call`:
16
16
17
17
```swift
18
18
structAdder {
@@ -121,21 +121,20 @@ A call syntax sugar would enable `BoundClosure` instances to be applied like nor
121
121
122
122
### Nominal types with one primary method
123
123
124
-
Some nominal types have a "primary method" that performs their main use. For example: calculators *calculate*, parsers *parse*, neural network layers *apply to inputs*, types representing functions *apply to arguments*, etc.
124
+
Some nominal types have a "primary method" that performs their main use. For example:
* Neural network layers *apply to inputs*: `layer.applied(to: input)`.
130
129
* Types representing functions *apply to arguments*: `function.applied(to: arguments)`.
131
130
132
131
Types that have a primary method usually call that method frequently. Thus, it may be desirable to sugar applications of the main method with call syntax to reduce noise.
133
132
134
-
Let’s explore neural network layers and string parsers in detail.
133
+
Let's explore neural network layers and string parsers in detail.
135
134
136
135
#### Neural network layers
137
136
138
-
[Machine learning](https://en.wikipedia.org/wiki/Machine_learning) models often represent a function that contains an internal state called "trainable parameters", and the function takes an input and predicts the output. In code, models are often represented as a data structure that stores trainable parameters, and a method that defines the transformation from an input to an output in terms of these trained parameters. Here’s an example:
137
+
[Machine learning](https://en.wikipedia.org/wiki/Machine_learning) models often represent a function that contains an internal state called "trainable parameters", and the function takes an input and predicts the output. In code, models are often represented as a data structure that stores trainable parameters, and a method that defines the transformation from an input to an output in terms of these trained parameters. Here's an example:
@@ -326,15 +325,15 @@ When type-checking fails, error messages look like those for function calls. Whe
326
325
327
326
```swift
328
327
add1("foo")
329
-
// error: cannot invoke ‘add1’ with an argument list of type '(String)'
328
+
// error: cannot invoke 'add1' with an argument list of type '(String)'
330
329
// note: overloads for 'call' exist with these partially matching parameter lists: (Float), (Int)
331
330
add1(1, 2, 3)
332
331
// error: cannot invoke 'add1' with an argument list of type '(Int, Int, Int)'
333
332
```
334
333
335
334
### When the type is also `@dynamicCallable`
336
335
337
-
A type can both have `call` members and be declared with `@dynamicCallable`. When type-checking a call expression, the type checker will first try to resolve the call to a function or initializer call, then a `call` member call, and finally a dynamic call.
336
+
A type can both have `call` members and be declared with `@dynamicCallable`. When type-checking a call expression, the type checker will first try to resolve the call to a function or initializer call, then a `call` member call, and finally a dynamic call.
338
337
339
338
### Direct reference to a `call` member
340
339
@@ -388,7 +387,7 @@ The proposed feature adds a `call` keyword. Normally, this would require existin
388
387
389
388
To maintain source compatibility, we propose making `call` a contextual keyword: that is, it is a keyword only in declaration contexts and a normal identifier elsewhere (e.g. in expression contexts). This means that `func call` and `call(...)` (apply expressions) continue to parse correctly.
390
389
391
-
Here’s a comprehensive example of parsing `call` in different contexts:
390
+
Here's a comprehensive example of parsing `call` in different contexts:
392
391
393
392
```swift
394
393
structCallable {
@@ -446,13 +445,13 @@ struct Adder {
446
445
}
447
446
// Option: `call` declaration modifier on unnamed `func` declarations.
448
447
// Makes unnamed `func` less weird and clearly states "call".
449
-
call func(_ x:Int) ->Int { … }
448
+
call func(_ x:Int) ->Int { ... }
450
449
}
451
450
```
452
451
453
452
This approach represents call-syntax delegate methods as unnamed `func` declarations instead of creating a new `call` declaration kind.
454
453
455
-
One option is to use `func(...)` without an identifier name. Since the word "call" does not appear, it is less clear that this denotes a call-syntax delegate method. Additionally, it’s not clear how direct references would work: the proposed design of referencing `call` declarations via `foo.call` is clear and consistent with the behavior of `init` declarations.
454
+
One option is to use `func(...)` without an identifier name. Since the word "call" does not appear, it is less clear that this denotes a call-syntax delegate method. Additionally, it's not clear how direct references would work: the proposed design of referencing `call` declarations via `foo.call` is clear and consistent with the behavior of `init` declarations.
456
455
457
456
To make unnamed `func(...)` less weird, one option is to add a `call` declaration modifier: `call func(...)`. The word `call` appears in both this option and the proposed design, clearly conveying "call-syntax delegate method". However, declaration modifiers are currently also treated as keywords, so with both approaches, parser changes to ensure source compatibility are necessary. `call func(...)` requires additional parser changes to allow `func` to sometimes not be followed by a name. The authors lean towards `call` declarations for terseness.
458
457
@@ -496,6 +495,10 @@ Also, we want to support direct references to call-syntax delegate methods via `
496
495
structAdder {
497
496
var base: Int
498
497
// Informal rule: all methods with a particular name (e.g. `func call`) are deemed call-syntax delegate methods.
498
+
//
499
+
// `StringInterpolationProtocol` has a similar informal requirement for
* A marker type attribute is not particularly meaningful. The call-syntax delegate methods of a type are what make values of that type callable - a type attribute means nothing by itself. In fact, there’s an edge case that needs to be explicitly handled: if a `@staticCallable` type defines no call-syntax delegate methods, an error must be produced.
510
+
* A marker type attribute is not particularly meaningful. The call-syntax delegate methods of a type are what make values of that type callable - a type attribute means nothing by itself. In fact, there's an edge case that needs to be explicitly handled: if a `@staticCallable` type defines no call-syntax delegate methods, an error must be produced.
508
511
* The name for call-syntax delegate methods (e.g. `func call` ) is not first-class in the language, while their call site syntax is.
509
512
510
513
#### Use a `Callable` protocol to represent callable types
@@ -514,8 +517,6 @@ We feel this approach is not ideal because:
514
517
structAdder: Callable {
515
518
var base: Int
516
519
// Informal rule: all methods with a particular name (e.g. `func call`) are deemed call-syntax delegate methods.
517
-
// `StringInterpolationProtocol` has a similar informal requirement for `func appendInterpolation` methods.
This can be achieved via Swift’s subscripts, which can have a getter and a setter.
540
+
This can be achieved via Swift's subscripts, which can have a getter and a setter.
540
541
541
542
```swift
542
543
foo[x, y] = x + y
543
544
```
544
545
545
-
Since the proposed `call` declaration syntax is like `subscript` in many ways, it’s in theory possible to allow `get` and `set` in a `call` declaration’s body.
546
+
Since the proposed `call` declaration syntax is like `subscript` in many ways, it's in theory possible to allow `get` and `set` in a `call` declaration's body.
546
547
547
548
```swift
548
549
call(x: T) ->U {
@@ -555,7 +556,7 @@ call(x: T) -> U {
555
556
}
556
557
```
557
558
558
-
However, we do not believe `call` should behave like a storage accessor like `subscript`. Instead, `call` ’s appearance should be as close to function calls as possible. Function call expressions today are not assignable because they can't return an l-value reference, so a call to a `call` member should not be assignable either.
559
+
However, we do not believe `call` should behave like a storage accessor like `subscript`. Instead, `call`'s appearance should be as close to function calls as possible. Function call expressions today are not assignable because they can't return an l-value reference, so a call to a `call` member should not be assignable either.
0 commit comments