aboutsummaryrefslogtreecommitdiff
path: root/docs/notes/version2.txt
blob: 7269e0e1b949ec19718ce03ac7423d1aa25c433e (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
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263


Types
-----

Elementary:

     void     --    ()

     s char   --    int8
     u char   --    byte   (=uint8)
     short    --    short  (=int16)
     u short  --    ushort (=sint16)
     int      --    int
     u int    --    uint
     long     --    -
     u long   --    -
     
     -        --    int0, int1 ...
     -        --    uint0, uint1 ...
     -        --    ring0, ring1 ...
     
     int x:3  --    unaligned int3
     
     bool     --    uint1
     
     size_t   --    count
     ssize_t  --    -

Enum:

    enum { a, b }
    int(a | b)

Struct:

    struct { int a; int b; }
    (int a, int b)

Union:

    union { int a; int b; }
    union(int a, int b)
        The types must be guaranteed to be compatible by any user of the
        union.
        
        Private types are in fact allowed, and this can be used to implement
        multiple inheritance. See the rules for private types.

Pointer:

    int *
    
    int* (if NULL is allowed, equivalent to int&?)
    int& (if NULL is not allowed)

    the compiler must check that the pointer points to a compatible
    value at compile time.

Array:

    int[]
    int[] (but accessing is an error in strict mode)
    
    int[5]
    int[5]
    
    int[length]
    int[length]

Strings, null-terminated:

    char[20] s
    byte[20] s
    
    char* s
    byte[strlen(s)+1]* s
    
    "test"
    "test"
        A null is always added at the end. Strings are UTF-8.

Function:

    int func(int a, int b)
    (int) func(int a, int b)
    
    int (*func)(int a, int b)
    (int) (int a, int b)* func
    
    (int result) func(int a, int b)
        Named return parameter

Variable arguments:

    int func(int a, ...)
    (int) func(int a, args...) constraint(x)
        args becomes an opaque type of unknown size. Unless a constraint
        is given it can only be accessed in unsafe mode.

Data hiding:

    typedef struct _a a
    typedef a = private
    
    struct _a { int b }
    typedef a = (int b)
    
    typedef a = (int #refcount, private)
        A struct where only the refcount is public.
        
        It's allowed to have a private and a non-private type of the same name,
        if the non-private parts are compatible.

Const:

    const int a = 0
    const int a = 0
    
    const value* find(const key *key)
    (const value* entry) find(const key& key)
    
    const makes everything after the keyword const. These are equivalent:
    
        const char *const s = "test";
        const byte[]* s = "test;

    typedef coord = const (int x, int y)
    coord a = (0, 1);
    coord b = (x: 0, y: 1);
        coord will be immutable, but can be created
        

Optional value (new):

    int?  order_number

Memory restrictions (new):

    int&none        -- No ownership of pointer (default)
    int&owned       -- Ownership of pointer is required
    (int #c)&refc   -- Reference counted. The type must be a pointer
                       to a struct, or an optional pointer to a struct.
                       The struct must contain a reference counter, whose
                       name must be prefixed with #.
    
    typedef node = (node*backptr prev, node*owned next, int value)
        The prev pointer must point to another node which owns the current
        node.

Constraints (new):

    int a constraint(a < 0)
    int a constraint(value < 0)
        The constraint must be satisfied when modifying to a, and is
        assumed to be satisfied when reading a value from a.
    
    () sqrt(int* a) precond(*a >= 0) postcond(*a >= 0)
        The precondition must be satisfied when calling the function.
        The function must satisfy the postcondition before it returns
    
    (int r) modify(int a) constraint(readonly == false)
        The constraint must be satisfied during the call of the function.
    
    typedef oddint = int constraint(value & 1 == 1)
        The constraint must be satisfied for any value of this type.
    
    void memcpy(restrict char *dest, restrict const char *src, size_t length)
    () memcpy(byte[length]& dest, const byte[length]& src, count length)
        constraint(distinct(dest, src))

Inheritance (new):

    typedef FileSystem = private;
    typedef FTPFileSystem = (FileSystem base, private);
    typedef HTTPFileSystem = (FileSystem base, private);
        The inheritance is just syntactic sugar. If you have a member called
        "base" in a struct then it will work as the base class.
        
        private is not a real type, and is not compatible with any other type.
        Hence FTP and HTTPFileSystem are incompatible (they have no common
        real type).

Multiple inheritance (new):
    
    typedef DatabaseColumn(Table) = private;
    typedef TypedColumn(Type) = private;
    typedef Column(Table,Type) = (
        union(DatabaseColumn(Table),TypedColumn(Type)) base,
        private
    );
        The rules for compatibility in unions apply.

Namespaces (new):

    typedef Car = private;
    typedef Car = (Car *trailer, string& regnum);
    
    namespace (Car) {
        
        -- Static method
        (bool) check_registration_number(string& regnum);
        
        -- Constructor (actually, it's just a static method)
        -- How should we handle stack allocation?
        --   1) with an extra parameter (like C++ does)
        --   2) with a flag
        --   3) with different methods?
        --   4) by returning (Car this) and having the caller sort out
        --      allocation?
        (Car* this) new(Car* trailer = NULL, string& regnum);
        
        -- Instance method
        () start(Car& this);
    }
    
    Car &c = Car.new("ABC123");
    c.start();


    -- Should we have two constructors, like this?
    -- problem: we overwrite the state of a class with init()!
        
        (Car this) init(Car* trailer = NULL, string& regnum)
            -- this is optional of course
            constraint(uninitialized(this))
        {
            this.trailer = trailer;
            this.regnum = regnum;
        }
        
        (Car* this) new(Car* trailer = NULL, string& regnum) {
            this = alloc();
            *this = init();
        }


Generic types (new):

    typedef list(T) = private
    typedef list(T) = (int length, T[length]* data)
        Definition of a generic type.
    
    () add(T)(list(T) this, const T& element, count size = alignedsize(T))
        constraint(size == alignedsize(T))

Expressions
-----------

Should IMO be mostly the same as C, except:
  * Different priority of operators. x & 1 == 0 should mean (x & 1) == 0
  * MAYBE we should remove post/pre addition/subtraction
  * MAYBE = should not return a value, except in cases like "a = b = z"
  * MAYBE < should be possible to write like -10 < x < 30

Exception modes
---------------

strict -- the compiler checks that no exceptions can occur at runtime
loose  -- the compiler inserts checks for exceptions so the program is
          terminated before an exception would occur.
unsafe -- no checks are done at runtime. exceptions may have undefined
          behaviour in some cases.