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
|
# 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);
}
```
With `var`:
```
var dist = { flt x, flt y -> sqrt(x*x*,y*y); }
```
Functions are called in the usual way:
`dist( 1.2, 2.3 ) // yields 2.59422435`
Functions can have zero arguments, in which case the `->` argument seperator is
optional. This allows any section of code to be "thunked" by wrapping it in
`{}`.
`just5 = { -> 5 } // With arrow`
`just5 = { 5 } // Without arrow`
Called:
`just5() // Returns 5`
Functions can be declared inside `struct`s, and will take a hidden `self`
argument to allow access to the struct members - basically the function becomes
a method.
Also new this chapter, fields with a leading underscore `_` are private fields,
and only accessible to 'self'.
```cpp
struct String {
u8[] _chars; // Private, not nullable, final, must be initialized in constructor
// Functions declared inside of a struct become instance methods
// and have access to the struct members.
val len = { -> _chars#; }
val at = { idx -> _chars[idx]; }
// 'self' keyword returns an instance of itself.
val append = { String? str ->
// Appending a null appends nothing
if( !str ) return self;
// Manual array copy _chars to cs
u8[] cs = new u8[_chars# + str.len()];
for( int i=0; i<_chars#; i++ )
cs[i] = _chars[i];
// Manual array copy str._chars to cs
for( int i=0; i<str.len(); i++ )
cs[_chars#+i] = str.at(i);
// Append returns a new String
return new String { _chars=cs; };
}
};
```
With some syntax sugar from the parser we can produce `Hello, Cliff`
with method calls.
```
String name = "Cliff";
String greet = "Hello";
return greet.append(", ").append(name);
```
There's only a little special syntax going on here with method calls. The
normal field lookup is used for `greet.append`, yielding a function-typed
value. Since it was loaded from the field, the function is **pre-bound**
(curried) to the `self` it was loaded from.
`{int->u8} atCliff = name.at; // The "at" for Cliff; function does not take a String anymore`
`var atHello = greet.at;`
`atCliff[0]; // Returns 'C'`
`atHello[0]; // Returns 'H'`
|