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
|
callback parameters
-------------------
C functions that take a callback function pointer often take a "void *user"
argument, which is passed to the callback. This could be made type safe by
making use of generic types:
() sort[T,U](list[T]^ elems;
int(U^ context; const T^ a,b) compare;
U^ context)
{
// ...
}
() main()
{
typedef Context = (bool reverse);
Context ctx = struct(false);
list[float] numbers;
numbers.init();
numbers.add(@4.5, _);
int compare(const Context^ ctx, const float^ a,b) {
float x = a^, y = b^;
if (ctx^.reverse) {
swap(@x, @y, _);
}
return (if x < y then -1 else if x > y then 1 else 0);
}
sort(numbers, @compare, @ctx);
}
If the context parameter is not used, we can use a "void" type:
int compare(const ()^ ctx; const float ^a,b) {
}
sort(numbers, @compare, @());
This could be simplified with some syntactic sugar:
() sort[T,U](list[T]^ elems;
int(U^ context; const T^ a,b) compare;
U^ context)
{
// ...
}
() main()
{
bool reverse = false;
list[float] numbers;
numbers.init();
numbers.add(@4.5, _);
int compare(const locals:type^ ctx, const float^ a,b) {
float x = a^, y = b^;
if (ctx^.reverse) {
swap(@x, @y, _);
}
return (if x < y then -1 else if x > y then 1 else 0);
}
sort(numbers, @compare, @locals);
}
where "locals" is automatically defined like this in every function:
namespace locals {
// a struct for all the local variables on the stack
typedef type = union(
(bool reverse);
(byte[4]; list[float] numbers); // offset is determined by the compiler
);
}
// pointer to the local variables on the stack
locals:type^ locals;
|