aboutsummaryrefslogtreecommitdiff
path: root/docs/notes/enum.txt
blob: 48ae13ef6f4fc8da018aee177c66a5a611afb1e2 (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

enum types
----------

This is the most simple kind of enumeration. The storage type
defaults to int and the values default to 0, 1, 2....

    typedef filestate = enum (
        unchanged,
        added,
        removed,
        modified,
    );

An enum can be used in a choice type (union in C). If the enum value is
immutable then the only the memory space needed for the choice value is
allocated.

    typedef filechange = (
        filestate state;
        choice(state) (
            unchanged(),
            added(int lines),
            removed(int lines),
            modified(int added_lines, int removed_lines),
        );
    );

enum values can have a value. On integer enums, it's incremented automatically.
Should enums start from zero (like C) or one (allows them to be merged with
an optional type which has the "none" value)?
Zero could work like false. Then the default start value should be one.
Merging enums with "none" isn't safe, because any value can be added later so
no value is safe to use as "none".

    typedef x = enum (
        three = 3,
        four,
        five,
    );

Negative values could count down (maybe this should be implemented with a
keyword instead, either just "negative" or something that specifies the range
of the enum):

    typedef error = enum (
        not_found = -1,
        no_access,
        invalid,
    );

enums can have non-integer values. These can't be incremented automatically.

    typedef color = enum (int r g b) (
        red    = (1,0,0),
        yellow = (1,1,0),
        green  = (0,1,0),
        blue   = (0,0,1),
        purple = (1,0,1),
    );


combined enumerations
---------------------

Enumerations may be combined with a union type (unions are similar to C unions,
except that all types must have disjoint values):

    typedef status = union(
        error,
        enum(connecting, requested, recieving, finished)
    );

    typedef parameter = union(
        error,
        uint16,
    );

The underlying bit representations must be disjoint so it's not possible to
combine for instance int and uint. In fact, all but one type in the union must
be enums or begin with enums (in case of structs).

It's possible to check if a union is of a certain type:

    status st;
    if (st is error) {
        // ...
    }

An enum can be converted to one of it's types. This is subject to compiler
and/or runtime checks depending on the compilation options.

    status st;
    
    error err = st as error;


We need to be able to reserve values for the enums (for instance in case a new
error code needs to be added):

    // syntax alternative 1:
    typedef error = enum(
        not_found = -0x1,
        no_access,
        invalid,
        max_error = -0x101,
    );

    // syntax alternative 2:
    typedef error = enum range(0x100) (
        not_found = -0x1,
        no_access,
        invalid,
    );
    
    // syntax alternative 3:
    typedef error = enum negative (
        not_found,
        no_access,
        invalid,
        max_error = 0x100,
    );
    
    // syntax alternative 4, with range-limited int types:
    typedef error = enum int[0,0x100] (
        not_found,
        no_access,
        invalid,
        max_error = 0x100,
    );



enums in arrays
---------------

An enum (or nested enum) that contains only values >= 0 or < 0 can be used as
an array index. Negative values are converted as -(n-1), so -1=0, -2=1, -3=2...

    string#[] errnames = ["Not found", "No access", "Invalid"];
    io:out << errnames[error:no_access] << io:endl;

An array type can specify that the index must be of a certain type:

    string#[error] errnames = ["Not found", "No access", "Invalid"];
    
    // same as above, but with explicit array indices
    string#[error] errnames = [
        .not_found: "Not found",
        .no_access: "No access",
        .invalid: "Invalid"
    ];


enums in switch/case
--------------------

TODO. There are several variants of this:

  * "switch/case/default" in C/Java
  * "switch/case/default" in C#
  * "case/a..b,c:" in Pascal
  * "alt" in Rust
  * key/value maps with functions or values in Python.
  * key/value maps with blocks



extensible enums in Java
------------------------

Enums can be made extensible with the following pattern in Java:

    public enum Values extends Value {
        A,
        B,
        C,
    }
    
    public interface Value { }