source: doc/proposals/tagged-struct.txt @ 577659b

Last change on this file since 577659b was 577659b, checked in by Andrew Beach <ajbeach@…>, 4 years ago

Added some more information to the tagged-struct proposal from the emails.

  • Property mode set to 100644
File size: 6.6 KB
1Proposal to add simple inhieritance to the language.
3Tagged structures allow for dynamic casting between types in a hierarchy.
4Children (rather pointers to) can be up-cast to their parents, a safe
5conversion that may recive language level support or even be implicit.
6Parents can be down cast to their children, which might fail if the underlying
7object is not of the child type, or a child of that.
9This does not however cause dynamic look-up. During function calls the
10underlying type is ignored, and the pointer type is used to type match the
11function call.
13The name tagged structure comes from tagged union, which carries a value to
14say which of the possible values is currently stored in the union. The idea
15here is similar, however the possibilities are more open ended.
17Alternate names include virtual structure and abstract structure.
22"struct" name [ "tagged" [ parent-name ] ] "{" fields "}"
24The keywords can change (although they currently reflect the concept name
25closely). More formally, in terms of grammar this adds:
28        ...
29        struct identifier tagged { struct-declaration-list }
30        struct identifier tagged parent-identifier { struct-declaration-list }
32"tagged" by itself create a tagged structure that is the root of a new tree.
33It has no parent tagged structure. If "tagged" is used with a parent than
34that is the parent of this node.
36Tagged structures have fields beyond the ones listed. Root tags have a type
37field added which give the type of the instance. Child tags prepend all of
38their parent's fields to their field list so they can be upcast.
40The type field may be public, if it is then it can be accessed through a
41simple field access "instance.type". The type field would then be able to be
42used to access the type object, which contains the information for the type.
43It may just be a pointer to the type object "*instance.type", although a
44lookup function could also be used.
49The central feature for tagged structs is a checked cast between pointer types
50to the structures. A cast is successful if the true type of the pointed object
51is of the type being cast to or any of its children, otherwise the cast
52returns null.
54The type field should also allow for equality comparison of types.
56Currently, with only these operations (and similar features) the type field
57could be hidden and the operations given through helper functions. However
58if the type object has more complex (or even open ended) information in it
59than providing direct access becomes very valuable.
64Adding to the field list would have to be handled during translation. The
65simple act of adding declarations should not be difficult, althought it might
66take a bit of work to find the parent's declarations.
68Type objects are also simple in to generate, they should just be global
69(program lifetime) structures. Getting there to be exactly one instance of
70each allows the pointer to the structure to be used as the type id, and that
71should be possible to do during linking.
73If a generic/polymorphic type is tagged its tagged would then be shared
74between all applications of that generic. Internal tags could be used to
75seperate these structures again, however it seems in most cases simply using
76the existing type parameters should provide the needed information.
81[is_]tagged[_struct](dtype T)
82True if the given T is a tagged struct of some kind. This promises that it has
83a type object, but nothing else.
85[is_]tagged_under(dtype parent, dtype child)
86True if child is a child type of parent. Requires that both are tagged structs
87and that child can upcast to parent.
92forall(dtype T | is_tagged(T), dtype U | is_tagged(U))
93T * dynamic_cast(U * value)
94The cast function, that safely converts the U* into a T*, returning null if
95the underlying object value points to is not a child type of T. A shorter name
96might be perfered. The runtime should be no more than linear with the depth
97of U in the inhiertance tree.
99bug#11 might require `bool dynamic_cast(T ** dst, U * src)` instead.
102Tagging Unions (Extention):
104Using this system as is does not really work if used on unions directly.
105No new options to the union can be added, as they must be able to upcast.
106Similarly, if options are removed, writing to an upcast union is invalid.
107To allow for growth each option would have to be a structure itself.
109Which brings us to "tagged struct union", ie. a union of tagged structures
110as opposed to tagging the union itself. This extention acts as a constraint.
111If unions are declared tagged instead of creating a new tagged type, all
112possible values of the union must be of that tagged type or a child type. If
113the tagged type is omitted then they must all be tagged but of any tagged
116As a short cut union_instance->type might get the type object of the loaded
117value. It should always be the same operation regardless so it saves
118abritarly picking a branch of the union to get the type object.
121Type Objects Fields (Extention):
123Adding fields to the type object allows data to be shared between instances
124of the same type. Such behaviour could be mimiced by creating a lookup
125function on the type object pointer, but this may be cleaner and more
128The type object fields follow similar rules to the fields on the tagged
129objects themselves, they must be additive. So any fields present on a
130type object will be present (and in the same place) on all of its children.
132This does mean that many type object structure types will have to be auto
133generated, and traversing up the tree might get a little wierd. That could
134be symplified by only allowing the root type to specify fields on the type
135object, so that the type object is consistant throughout that particular tree.
136And hence the type_object pointers would also be consistant as the type they
137point to would never change.
139struct Example tagged {
140        tagged char const * const type_name = "Example";
141        int data;
144Creates a tagged structure that has no parent, stores an integer and the type
145object also has an extra field that stores a string on the type object.
146This can be accessed by using member access on the type object, as a regular
149Type object fields will have to allow initialization on their declaration,
150and declarations of children as well, as they are not assotiated with the
151later instances of the tagged structure.
153        ...
154        tagged void (*dtor)(tagged Example * this);
155        ...
157Sub-Extention, not sure how it would work but some way to have a "dynamic"
158field that is considered the type of the current tagged struct might be useful
159for things like specifying a deconstructor. In this case, the following code
160will clean up any child type of Example:
162Example * ex = get_some_example();
Note: See TracBrowser for help on using the repository browser.