aboutsummaryrefslogtreecommitdiff
path: root/notes/avoiding_builtins.txt
blob: eb72f8d4418dc43511c3e5389872034b9ecd716d (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
264
265
266
267
268
269
270
271
272
273
274

Is it possible to avoid builtin types entirely?
That is, have only plain old classes / all types are classes.

Problems to solve:

* Identity-less vs "undecided" vs identity-full types:
    - Bool, Int, String, and "value types" are identity-less.
    - Objects that do I/O of some kind are identity-full.
    - Whether a type is identity-less or identity-full affects API, so it could
      make sense to have "undecided" as the default. Types in undecided mode
      wouldn't have `==` or `<>` defined, and at the ABI level they would
      only allow operations that are allowed on both (so no stack allocation
      for example).
* Enumerations:
    - `Bool` can be a closed enum of `True` and `False`
* Integers:
    - Integers could be a special integral/numeric/range/etc. type with a
      defined minimum and maximum value.

Related problem: Comparing unknown objects
------------------------------------------

This could happen in generic types, for example with a "Key" type of a HashMap
or similar. Perhaps it is better to just ignore this and skip supporting it?
It adds a lot of complexity for what seems to be quite limited value.

Could have IntMap, StringMap, etc.

Or could pass (limited?) runtime type information to generic functions/types?
And maybe store it in generic types?
Or some implicit parameter in the constructor, and explicit storage in some
instance variables? Perhaps a `TypeInfo T` type?

Or could have a type parameter that is restricted to a known set of types,
have specialized classes: List_String.slul, List_Int.slul, ListAnyInt32.slul
(this will make it impossible to set the key parameter to another parameter,
such as `Map K String` unfortunately).

    class Map K V
    typeparam K
        String
        Int
        Any8
        Any16
        Any32
        Any64
    typeparam V

or:

    class Map K V
    typebound K
        String
        Int
        Any8
        Any16
        Any32
        Any64

The default typebound should probably be the union of any reference type and
Any64? That could be called `Any64OrRef`.
Or in the bootstrap subset: `Any32OrRef`.

Syntax test for enums and integers
----------------------------------

Enumeration:

    class Bool
    enum
        False
        True
    end

Integer:

    class Int
    # find some keyword that doesn't that doens't start with `int`
    integral
        min 0
        max 2^31-1
    end
    numeric
        min 0
        max 2^31-1
    end
    range
        min 0
        max 2^31-1
    end

Syntax test for identity-less vs identity-full types
----------------------------------------------------

Should it be a "block" with (or without) `end` or not?

    # Syntax 1 (for implementation files?)
    class Point

    value
        int x
        int y
    end

    # Syntax 2 (for interface files?)
    class Point

    value
        int x
        int y

    # Syntax 3 (could work in both)
    class Point
    value

    int x
    int y

Which keywords to use for identity-less/full/undecided?
-------------------------------------------------------

See also `class_kinds_keywords.txt`

It could use the words in the header, or words that describe whether the
type is comparible / has an `==` operator, or some completely different word.

* For identity-less types?
    value
    struct
    record
    data
* For undecided types?
    - Should it be the default? (And not have a keyword)
* For identity-full types?
    identity
    properties
    state

Syntax test of just defining whether operator `==` is defined
(best solution?)

    class Point
    operator `==`   # default implementation
    ...

    class File
    has_identity
    ...

    class Undecided
    ...


Perhaps have a `storage` keyword?
---------------------------------

    class Point
    storage value
        int x
        int y
    end

    class Bool
    storage enum
        False
        True
    end

    class Int
    storage number
        min 0
        max 2^31-1
    end

    class Float
    storage number
        float 32
    end

    class File
    storage unique
        int fd
    end

    class Undecided
    storage
        int x
    end

An observation:

Private types can only be reference types!
- But there are still internal-only types (not exposed in interface file).

Merge immutable objects and enums?
----------------------------------

Enums could be implemented similar to singleton objects, except that they
would still be identified by their ordinal/enum number:

    class SomeEnum

    # May not have modifiable/mutable fields and field types!
    int x
    bool b

    # This restricts the set of values
    enum
        ValueA = new  1 True
        ValueB = new  0 False
        ValueB = new  2 True
    end

This could be implemented as an integer + an array of constant structs
with the values (1,True), (0,False) and (2,True) as above.
On platforms where it is inefficient to access global const data (`.rodata`),
the structs could be accessed via a function. In C style code it could be:

    struct SomeEnum__struct {
        unsigned x;
        bool b;
    };
    void SomeEnum__getstruct(unsigned enumvalue, struct SomeEnum__struct *out);

Example without any associated structure:

    class Bool

    enum
        False
        True
    end

The constructor calls (`= new ...`) should only appear in implementation files,
never in interface files.


Unifying Enum, NumericRange, service types, value types and refererence types?
------------------------------------------------------------------------------

Service type specifications also appear at the start of a class, just like
an integer-range or enum would. Could these two be unified? Would it make
sense?

Enum example:

    is Enum
        ValueA
        ValueB

Integer example:

    is NumericRange
        min = 0
        max = 255

Service type example:

    is CommandMain "test"
        File outfile = input_file "-o"
        Int counter! = 0

Class of value type:

    is Value
        Int x
        Int y

Class of reference type:

    is Unique
        Int filedescriptor
        Int position
        FileMode filemode