summaryrefslogtreecommitdiff
path: root/chapter17/README.md
blob: 95cc397ec430ec0a66a6d6fd0b932a7e097fc99c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# Chapter 17: Syntax Sugar


## Post-increment

Allow `arg++` and `arg--` with the usual meanings; the value is updated and the
expression is the pre-update value.  Greedy match is used so `arg---arg` parses
as `(arg--)-arg`.

Also allows `s.fld++` and `ary[idx]++`, and their `--` variants.


## var & val

`var` can be used in the `type` position to indicate a "variable" (mutable
value), whose type will be inferred from the initalizing expression.

`val` is the same as `var`, except it is a "value" (not mutable).

The inferred value is the `glb` of the peephole type, which means `var` and
`val` will not infer types like `u8` or `f32`, instead inferring `int` and
`flt` respectively.  Struct types will always infer as nullable, so e.g. 

`var s = new S;` 

infers as

`S s? = new S;`


## Initialized fields are immutable by default

Typed field declarations with an initializer are immutable by default, and can
be made mutable with a leading `!`.  `var` and `val` keep their current sense.
Fields are immutable at the end of either constructor, but can be changed
during construction.


Examples:


```java
struct Point { int x,y; };  // Fields x and y are not initialized, mutable
Point p = new Point;
p.x++;                      // Mutate is ok
return p.x;
```

```java
struct Point { int x=3,y=4; };  // Fields x and y are initialized, immutable
Point p = new Point;
p.x++;                          // Error!
return p.x;
```

```java
struct Point { int x=3,y=4; };  // Fields x and y are initialized, immutable
Point p = new Point { x=x*x; y=y*y; }; // Ok to mutate in the constructor
p.x++;                          // Error!
return p.x;
```

```java
struct Point { int !x=3, !y=4; }; // Fields x and y are initialized, mutable
Point p = new Point; 
p.x++;                            // Mutate is OK
return p.x;
```

```java
struct Point { var x,y; }; // Error, var and val require an initializer
Point p = new Point; 
p.x++;
return p.x;
```

```java
struct Point { var x=3,y=4; };  // Fields x and y are mutable
Point p = new Point; 
p.x++;                          // Mutate is OK
return p.x;
```

```java
struct Point { val x=3,y=4; };  // Fields x and y are immutable
Point p = new Point; 
p.x++;                          // Error!
return p.x;
```


## Deep Immutability (proposal)

```cpp
struct Bar { int x; };
Bar  b  = new Bar; /* b = null; *//* b.x++; */ // immutable & deep immutable
Bar !b  = new Bar;    b = null;   /* b.x++; */ //   mutable & deep immutable
Bar  b! = new Bar; /* b = null; */   b.x++;    // immutable & deep   mutable
Bar !b! = new Bar;    b = null;      b.x++;    //   mutable & deep   mutable (ignoring NPE)
val  b  = new Bar; /* b = null; *//* b.x++; */ // immutable & deep immutable
var  b  = new Bar;    b = null;      b.x++;    //   mutable & inherits deep mutability from RHS
```


## Trinary

Allow `pred ? e_true : e_false`.  Also allow `pred ? e_true`, where the false result
is the zero type version of the true result.







C++-style for-loop
for-interator
trinary
switch






# Chapter 18: Functions

Some thinking on function syntax:

Function Types:
```
{ argtype, argtype, ... -> rettype }
```

Leading `{` character denotes the start of a function or function type.

Functions are normal variables and assigned the same way:

```functiontype var = function-typed-expr```

Functions themselves using the same syntax with as types, but filled in:

```
{ int x, int y ->
  sqrt(x*x+y*y);
}
```

Used in a declaration statement:
```
// TYPE        VAR  =   EXPR
{flt,flt->flt} dist = { flt x, flt y ->
  sqrt(x*x+y*y);
}
```

Because it gets clunky to write the function type, and because it can be
directly inferred from forwards-flow analysis (not even HM) which we're already
doing at parse-time, we add a new variable declaration syntax: "var" - for
auto-inferring variable types.  Not allowed in function headers.
```
var dist = { flt x, flt y -> sqrt(x*x*,y*y); }
```

`var` can be used for normal variables as well:

```
// Newtons approximation to the square root
var sqrt = { flt x ->
    var guess = x*x/2;
    while( 1 ) {
        var next = (x/guess + guess)/2;
        if( next == guess ) break;
        guess = next;
    }
    guess;
}
```

When inferring pointer types, it will use the `glb` of the initial expression
type, which may not be what you want:

```
struct LLI { LLI? next; int i; };
var head = LLI(); // Want this declared not-null, but GLB will allow null
head = null;      // Allowed
```