Skip to content

Commit 1412763

Browse files
committed
Change context function syntax
Instead of `A? => B`, use a joint operator `A ?=> B`. The two separate operators look more familiar, but that can also be a problem since they suggest that `A?` is a nullable or in other ways optional type. By joining `?` and `=>` into a new `?=>` operator we avoid that misconception and also keep the possibiliy to use postfix `?` at some point in the future (maybe for the fancy unboxed options?).
1 parent c536fd7 commit 1412763

File tree

2 files changed

+22
-21
lines changed

2 files changed

+22
-21
lines changed

docs/docs/reference/contextual/context-functions-spec.md

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,12 @@ title: "Context Functions - More Details"
66
## Syntax
77

88
Type ::= ...
9-
| FunArgTypes ‘?’ ‘=>’ Type
9+
| FunArgTypes ‘?=>’ Type
1010
Expr ::= ...
11-
| FunParams ‘?’ ‘=>’ Expr
11+
| FunParams ‘?=>’ Expr
1212

1313
Context function types associate to the right, e.g.
14-
`S? => T? => U` is the same as `S? => (T? => U)`.
14+
`S ?=> T ?=> U` is the same as `S ?=> (T ?=> U)`.
1515

1616
## Implementation
1717

@@ -28,7 +28,7 @@ trait ContextFunctionN[-T1 , ... , -TN, +R] {
2828
Context function types erase to normal function types, so these classes are
2929
generated on the fly for typechecking, but not realized in actual code.
3030

31-
Context function literals `(x1: T1, ..., xn: Tn)? => e` map
31+
Context function literals `(x1: T1, ..., xn: Tn) ?=> e` map
3232
context parameters `xi` of types `Ti` to the result of evaluating the expression `e`.
3333
The scope of each context parameter `xi` is `e`. The parameters must have pairwise distinct names.
3434

@@ -54,7 +54,7 @@ Note: The closing paragraph of the
5454
[Anonymous Functions section](https://www.scala-lang.org/files/archive/spec/2.12/06-expressions.html#anonymous-functions)
5555
of Scala 2.12 is subsumed by context function types and should be removed.
5656

57-
Context function literals `(x1: T1, ..., xn: Tn)? => e` are
57+
Context function literals `(x1: T1, ..., xn: Tn) ?=> e` are
5858
automatically created for any expression `e` whose expected type is
5959
`scala.ContextFunctionN[T1, ..., Tn, R]`, unless `e` is
6060
itself a context function literal. This is analogous to the automatic

docs/docs/reference/contextual/context-functions.md

Lines changed: 17 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,11 @@ _Context functions_ are functions with (only) context parameters.
77
Their types are _context function types_. Here is an example of a context function type:
88

99
```scala
10-
type Executable[T] = ExecutionContext? => T
10+
type Executable[T] = ExecutionContext ?=> T
1111
```
12-
A context function is applied to synthesized arguments, in
13-
the same way a method with context parameters is applied. For instance:
12+
Context function are written using `?=>` as the "arrow" sign.
13+
They are applied to synthesized arguments, in
14+
the same way methods with context parameters is applied. For instance:
1415
```scala
1516
given ec as ExecutionContext = ...
1617

@@ -20,26 +21,26 @@ the same way a method with context parameters is applied. For instance:
2021
f(2) // argument is inferred
2122
```
2223
Conversely, if the expected type of an expression `E` is a context function type
23-
`(T_1, ..., T_n)? => U` and `E` is not already an
24+
`(T_1, ..., T_n) ?=> U` and `E` is not already an
2425
context function literal, `E` is converted to an context function literal by rewriting to
2526
```scala
26-
(x_1: T1, ..., x_n: Tn)? => E
27+
(x_1: T1, ..., x_n: Tn) ?=> E
2728
```
2829
where the names `x_1`, ..., `x_n` are arbitrary. This expansion is performed
2930
before the expression `E` is typechecked, which means that `x_1`, ..., `x_n`
3031
are available as givens in `E`.
3132

32-
Like their types, context function literals are written with a `?` after the parameters. They differ from normal function literals in that their types are context function types.
33+
Like their types, context function literals are written using `?=>` as the arrow between parameters and results. They differ from normal function literals in that their types are context function types.
3334

3435
For example, continuing with the previous definitions,
3536
```scala
3637
def g(arg: Executable[Int]) = ...
3738

38-
g(22) // is expanded to g((ev: ExecutionContext)? => 22)
39+
g(22) // is expanded to g((ev: ExecutionContext) ?=> 22)
3940

40-
g(f(2)) // is expanded to g((ev: ExecutionContext)? => f(2).with(ev))
41+
g(f(2)) // is expanded to g((ev: ExecutionContext) ?=> f(2).with(ev))
4142

42-
g((ctx: ExecutionContext)? => f(22).with(ctx)) // is left as it is
43+
g((ctx: ExecutionContext) ?=> f(22).with(ctx)) // is left as it is
4344
```
4445
### Example: Builder Pattern
4546

@@ -79,13 +80,13 @@ Then, the `table`, `row` and `cell` constructor methods can be defined
7980
with context function types as parameters to avoid the plumbing boilerplate
8081
that would otherwise be necessary.
8182
```scala
82-
def table(init: Table? => Unit) = {
83+
def table(init: Table ?=> Unit) = {
8384
given t as Table
8485
init
8586
t
8687
}
8788

88-
def row(init: Row? => Unit) with (t: Table) = {
89+
def row(init: Row ?=> Unit) with (t: Table) = {
8990
given r as Row
9091
init
9192
t.add(r)
@@ -96,14 +97,14 @@ that would otherwise be necessary.
9697
```
9798
With that setup, the table construction code above compiles and expands to:
9899
```scala
99-
table { ($t: Table)? =>
100+
table { ($t: Table) ?=>
100101

101-
row { ($r: Row)? =>
102+
row { ($r: Row) ?=>
102103
cell("top left").with($r)
103104
cell("top right").with($r)
104105
}.with($t)
105106

106-
row { ($r: Row)? =>
107+
row { ($r: Row) ?=>
107108
cell("bottom left").with($r)
108109
cell("bottom right").with($r)
109110
}.with($t)
@@ -119,7 +120,7 @@ object PostConditions {
119120

120121
def result[T] with (r: WrappedResult[T]) : T = r
121122

122-
def (x: T) ensuring[T](condition: WrappedResult[T]? => Boolean): T = {
123+
def (x: T) ensuring[T](condition: WrappedResult[T] ?=> Boolean): T = {
123124
assert(condition.with(x))
124125
x
125126
}
@@ -128,7 +129,7 @@ import PostConditions.{ensuring, result}
128129

129130
val s = List(1, 2, 3).sum.ensuring(result == 6)
130131
```
131-
**Explanations**: We use a context function type `WrappedResult[T]? => Boolean`
132+
**Explanations**: We use a context function type `WrappedResult[T] ?=> Boolean`
132133
as the type of the condition of `ensuring`. An argument to `ensuring` such as
133134
`(result == 6)` will therefore have a given of type `WrappedResult[T]` in
134135
scope to pass along to the `result` method. `WrappedResult` is a fresh type, to make sure

0 commit comments

Comments
 (0)