summaryrefslogtreecommitdiff
path: root/chapter18/README.md
blob: 606ac9a8f625805370711d5fd255e72a46cb8b7f (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
# 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'`