aboutsummaryrefslogtreecommitdiff
path: root/notes/integer_types.txt
blob: d4ddfa959af5121454f0dc01460825c64d215b1d (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

Integer types
=============

Option 1: int/uint + (u)int8..int64 or even int128
Option 2A: int with range (default is int32), compiler chooses representation
    Bonus: Gets an implicit `eint32` type, which is 0..2^31-1
    Bonus: A range with explicit infinite bound(s) could be handled as a
           bigint.
    U8/I8..U64/I64 could be RTL-defined types. Maybe even U128/I128
    Problem 1: Should there be implicit packing in structs?
               Maybe not without an explicit bitfield container?
    Problem 2: Increasing range can change ABI. But it kind of already
               changes API, so maybe it's a non-issue?
               (But this could lead to permanentization of typos or
                off-by-one errors...)
    Problem 3: Tricky to extend to floating point types.
               That would also need precision.
               Also, should such floats be based, i.e. should
               "float >= 1.0" have 1.0 represented as 0.0?
               That would increase accuracy, but wouldn't work well
               with operations other than addition/subtraction.
    Problem 4: Needs non-pointer types for custom integer types.
               But maybe this is good to have anyway, in particular for
               integer types that shouldn't be mixed up.
Option 2B: int with range, int64/uint63, compiler chooses representation.
    One keyword for unsigned integers (uint63 by default).
    Another keyword for signed integers (int64 by default).
    Yet another keyword for custom-range integers.
    Keywords / Type names:
        * Different keywords?
            Pos / Signed / Number 0..9
        * Signed as a prefix, like C?
            num / signed num / num 0..9
            num / signed / num 0..9
Option 3: bigint by default unless a range is specified.
    Problem 1: This could lead to code that is inefficient by default.


Syntax for range-less variables:

    # Titlecase type (an ordinary type defined in the stdlib?)
    # This is tricky because:
    #  1) int needs range syntax
    #  2) the compiler needs to know bool in boolean expressions
    # Or maybe Int/Bool could still be in some kind of built-in "prelude" file
    Int n = 0
    Bool b = false
    # lowercase type (special case for int,bool)
    int n = 0
    bool b = false
    # With Option 2B:
    num n = 0
    signed d = -2
    float p = 0.5
    # Type inferrence. This is fine as long as there isn't arithmetic
    # operations that could extend the range indefinitly.
    # With artihmetic operations, it becomes trickier (but maybe
    # 0..2^31-1 could be the default range? Or -2^31..2^31-1?)
    n = 0
    b = false

Syntax for variables with restricted range:

    # with space inbetween
    Int 0..=9 n = 0
    int 0..=9 n = 0
    # with space and hyphesminusdash (why can't it simply be called "dash"...)
    int 0-9 n = 0
    int 0~9 n = 0  # <-- but ~ looks to similar to - and is less intuitive to make
    # Could perhaps work with Maps also:
    Map Int-String n = 0
    Int->String n = 0
    # with intN..n syntax
    Int..=9 n = 0
    int..=9 n = 0
    # With parentheses vs not
    int(0-9) n = 0
    int 0-9  n = 0
    int 0-9 n = 0
    # with intN-N syntax, with intN for 2^N types
    int-9 n = 0  # maybe skip this?
    int0-9 n = 0
    int0-* n = 0
    int64 n = 0
    int* n = 0
    # with iN-N syntax
    # note 1: i-9 is also an expression, so the parser/tokenizer
    # would have to be clever.
    # note 2: identifiers wouldn't be able to start with `i` followed by
    # a number. E.g. you can have `i2` as a variable name.
    i-9 n = 0  # <- ambiguous, but could be skipped
    i0-9 n = 0
    i0-* n = 0
    i64 n = 0
    i* n = 0

    # With option 2B:
    num<=99 n = 99
    num 1<=99 n
    signed -10<=10 d
    num ..99 n = 99
    num 1..99 n
    signed -10..10 d
    # or even
    0..99 n = 99
    1..99 n
    -10..10 d

    # Or, have a longer syntax BUT instead encourage custom types
    type MyNum = int 0..=9
    type MyNum = int from 0 to 9
    ...
    MyNum n = 0

Syntax with inferred range (maybe easy to get wrong?)


    func f
        int i
        int j
    constraints
        i >= 0
        i <= 10
    code
        i = 0
        while i < 10
            i = i+1
        j = get_number
        j += 1
        assert m >= 0
        assert m < 10
        ...
    end

Problem with wrapping types
---------------------------

When the `wrapping` keyword is in a separate location, e.g. in the definition
of a function parameter, it is easy to create confusing code:

    somefunc (65536*65536*65536*65536)

That will overflow and result in a zero value. It would be better if an explicit
`wrapping` keyword was required:

    somefunc (wrapping 65536*65536*65536*65536)