aboutsummaryrefslogtreecommitdiffhomepage
path: root/notes/type_syntax_2022.txt
blob: fe2dbd0310dcf31dea89eeb6cfedf81d5139ec4b (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

Syntax for types and declarations
=================================

Shortened type definitions?
---------------------------
Replace the "type I = ..." syntax with the following?

Type definitions:

    class I { ... }
    record I { ... }
    enum I { ... }
    error I { ... }
    # Should it be possible to define function types?
    # Or should function types always go into records?
    # Or should there a separate keyword for function types?
    # - functype? callback? ...?
    callback Compare<T>(T a, T b) -> ComparisonResult
    functype Compare<T>(T a, T b) -> ComparisonResult

Declarations of private types

    class I
    record I
    enum I
    error I

Disadvantages:
- Does not allow definitions of integer types
- It is not obvious to the user that non-class types can have
  methods and "constructors"/typescopes
- Type declarations can be confused with global variables.

Order of declaration
--------------------
Switch to "right-to-left" declarations:

    int[5] ref arr      <-- reference to array of length 5 of int

Should generics syntax be switched around also?

    <int,byte>Map m

Types vs other identifiers
--------------------------
A distinction between names of types and variables/constants/fields/funcs
is important for two reasons:

1. Syntax highlighting can color types in a different colors
   (this makes declarations stand out more)
2. Types can start with an identifier, so no "ref" or "data" keyword is
   needed in declarations.
   Declarations start with uppercase, and expressions with lowercase.

    Uppercase, _Uppercase = type
    lowercase, _lowercase = variable/constant/field/func
    _1 = forbidden


Avoiding the "ref" keyword
--------------------------
Functions:
- Remove the "ref" keyword completely. It doesn't make sense to distinguish
  between "ref" and "non-ref" funcs, and function references might be
  implemented as something that is not a pointer, or a different kind of
  pointer than a normal data pointer.

Objects:
- Objects with identity should always be passed by reference, so the "ref"
  keyword is redundant.

Records, enums and elementary types:
- These may be passed by value, so there could more than one "instance" of
  what appears to be the same instance. So pointers don't work well here.
  Also, small records, enums and numbers may have sub-byte sizes/boundaries,
  so pointers won't work anyway.

Strings:
- Single characters are special (encoded in the pointer), so pointers don't
  work here either.

Arrays:
- Arrays should work like records.

Qualifiers when parameter needs to be passed by reference
---------------------------------------------------------
"var", "threaded", "aliased" could be used for those purposes.
There is no point in explicitly passing a non-aliased constant
parameter by reference. The compiler can decide automatically
when to pass by reference or by value.

Qualifiers in classes/records/arrays
------------------------------------
In classes and records, it is necessary to specify whether the
item should be inlined or not, when it is a structure or array.

    type A = object {
    #class A {
        B inplace x        # type structure must be known (i.e. cannot be private in place of declaration of A)
        B ref y
        int[] ref a
        int[3] inplace b   # arrays can only be inplace-allocated if they have a compile-time constant size
        inplace B[3] inplace c  # array is inplace allocated, and so are the elements
    }

New "out" qualfier for parameters
---------------------------------
Unlike "writeonly", this MUST be initialized in all code paths (except on error).

Qualifiers on variables/parameters
----------------------------------
It can be desirable to have modifiable references also.
That could be written like this:

    func do_stuff(int out result)
    {
        File? var f = find_file("a.txt")
        if f == none {
            f = find_file("b.txt")
            result = 2
        } else {
            result = 1
        }
    }

Qualifiers on arrays
--------------------
There are several things that can be controlled by qualfiers:
- the field (if the array is in a struct)
- the array size
- the array "slots"
- the array "element contents"

Field:
    int[] ref a         <-- Reference to an array
    int[] var ref a     <-- Modifiable reference to an array

Array size:
    int[var] ref a

Array "slots":
    Buffer var[] ref a      <-- "Buffer" objects can be exchanged in list, but not modified themselves

Array "element contents":
    var Buffer[] ref a      <-- "Buffer" objects themselves can be modified, but not exchanged in list.

Error enums
-----------
Like enums, but can be used as follows:

    type FileError = error {
    #error FileError {
        not_found
        permission_denied
    }

    func .open(string filename) -> File or FileError

...in impl file:

    func work()
    {
        File f1 = .open("1.txt") or FileError e1 {
            ...handle error...
        }
        File f2 = .open("2.txt") or goto fail
        ...
        return
      fail:
        # XXX how to get the error code?
        ...handle error...
    }