blob: 0774e184f5613c74a83f8a622eb8f474ab0d4270 [file] [log] [blame]
MG Mud User88f12472016-06-24 23:31:02 +02001CONCEPT
2 structs
3
4INTRODUCTION
5 structs are, next to arrays and mappings, a way to group a
6 collection of value together.
7
8 A struct holds a fixed number of values, called 'members', and
9 allows to access them by their given name. The name is resolved
10 when the LPC code is compiled, making struct member access as fast
11 as array member access.
12
13 structs are passed by reference.
14
15
16DEFINITION
17 A new struct type has to be defined at the top level of an
18 object. For example
19
20 struct Foo {
21 int one, *two;
22 struct Bar three;
23 };
24
25 defines the new struct 'Foo' with three members: integer 'one',
26 integer array 'two', and struct Bar 'three'
27
28 It is possible to 'inherit' structs from each other. Given above
29 definition of struct Foo, the following definition
30
31 struct Quux (Foo) {
32 int four;
33 };
34
35 is equivalent to the definition
36
37 struct Quux {
38 int one, *two;
39 struct Bar three;
40 int four;
41 };
42
43
44 The usual visibility modifiers apply, e.g.
45
46 protected struct Bang {...};
47
48
49 struct definitions are promoted through inheritance like functions,
50 with the difference that all structs live in the same flat namespace.
51 This means: a struct defined in a program is visible in _all_
52 inherited programs, regardless of how deep the inheritance is
53 nested. This also means that in one program there must not be
54 two structs, inherited or not, with the same name.
55
56
57 To declare a struct without defining it, write:
58
59 struct Quux;
60
61 This notation is useful if you have two structs referencing
62 each other:
63
64 struct Quux;
65
66 struct Bar {
67 struct Quux quux;
68 };
69 struct Quux {
70 struct Bar bar;
71 };
72
73
74USAGE
75 To use a struct, its definition must be visible - either because it
76 is defined in the object compiled, or it has been inherited.
77 (Note: #include'ing structs does not what you think it does: in
78 LPC it constructs a new struct type whereever it is included).
79
80
81 A variable to hold a struct is defined like this:
82
83 struct Foo var;
84
85 and similar for function arguments:
86
87 void fun (struct Foo arg)
88
89
90 Just writing 'struct Foo var' however does not _create_ a struct,
91 it just creates a variable capable of holding one. To assign a value
92 to the variable upon creation, assign it with a struct value, either
93 from another variable or from a literal struct:
94
95 struct Foo var = (<Foo>);
96
97
98 Literal structs are written using (<>) as delimiters:
99
100 (<Foo>)
101 creates an empty instance of struct Foo
102
103 (<Foo> 1, ({ 2 }), bar)
104 creates an instance of struct Foo, and assigns 1 to member
105 'one', ({ 2 }) to member 'two', and the content of variable
106 bar to member 'three'.
107
108 (<Foo> two: ({ 2 }) )
109 creates an instance of struct Foo which is all empty except
110 for member 'two' which is assigned the value ({ 2 }).
111
112 It is not possible to use both named and unnamed initializers
113 in the same literal.
114
115
116 A struct member is accessed using the -> operator:
117
118 struct Foo var = ...;
119
120 var->one = 1;
121
122
123 It is possible to compute struct lookups at runtime:
124
125 struct Foo bar = ...;
126 string member = "one";
127
128 bar->(member) = 1; // sets bar->one to 1
129 bar->(0) = 1; // sets bar->one to 1
130
131
132 When using struct values held in variables/expressions of type
133 'mixed', the 'mixed' value should to be casted to the struct
134 value. The cast can be omitted if the looked-up member exists
135 in only one struct (and its children) known to the compiler:
136
137 struct Foo { int one; };
138 struct Bar { int two; };
139 struct Baz { int two; };
140 mixed var;
141
142 var->one // looks up Foo->one
143 (struct Foo)var->one // looks up Foo->one
144 var->two // ERROR: ambiguous lookup
145 (struct Bar)var->one // looks up Bar->one
146
147
148USAGE IN CLOSURES
149 The #'(< operator can be used in lambda closures to create a
150 struct; the type of the struct is given by the 'template'
151 struct passed as first argument. The content of the template
152 struct is irrelevant, so an empty struct suffices. For
153 example, to create an instance of struct Foo:
Zesstra7ea4a032019-11-26 20:11:40 +0100154
MG Mud User88f12472016-06-24 23:31:02 +0200155 ({ #'(<, (<Foo>), 1, ({ 2 }), (<Bar>) })
156
157 The order of the member values is the order in which they
158 appear in the struct definition.
159
160 To access a struct member in a lambda closure, use the #'->
161 operator with the name of the member as double-quoted symbol
162 or literal string:
163
164 ({ #'->, struct-expression, ''one })
165 ({ #'->, struct-expression, "one" })
166
167
168MISCELLANEOUS
169 Internally structs can be identified by the ID string
170 returned from get_type_info(). This string contains the name
171 of the struct, the name of the program its type was defined in,
172 and the ID number of the program. However, do not rely on
173 a particular format of this string!
174
175 Support for structs is signaled by the macro __LPC_STRUCTS__.
176
Zesstra7ea4a032019-11-26 20:11:40 +0100177 Though structs are tied to the program the are defined in,
178 re-compiling a program doesn't make the struct types
179 incompatible. Even if the newly compiled struct has a
180 different structure it will be accepted by routines that
181 expect the old struct definition. When members disappeared
182 in the new struct definition, read access to those members
183 will return 0, write access to vanished members however
184 will result in a runtime error.
MG Mud User88f12472016-06-24 23:31:02 +0200185
186
187EXAMPLES
188 Suppose we have two objects: a monster, and a monster
189 coordinate tracker, and we want to use a struct to store the
190 coordinate:
191
192 -- monster_coordinate.c --
193 struct Coordinate { int x; int y; };
194
195 -- monster_tracker.c --
196 inherit "monster_coordinate";
197
198 void track (struct Coordinate coord) { ... }
199
200 -- monster.c --
201 inherit "monster_coordinate";
202
203 int move (..) {
204 ...
205 "monster_tracker"->track( (<Coordinate> my_x, my_y) );
206 }
207
208 Note that using '#include "monster_coordinate.c"' instead of inherit
209 won't work. While the objects would compile, the first call to
210 track() would cause a runtime error of the type
211
212 Illegal type to struct->(): struct Coordinate (/monster.c #234),
213 expected struct Coordinate
214 (/monster_tracker.c #552)
215
216
217HISTORY
218 structs were fully implemented first in LDMud 3.3.246.
219 The implementation was revised in LDMud 3.3.344.
220 The reactivation of unchanged structs in object updates was
221 implemented in LDMud 3.3.417.
222
223
224SEE ALSO
225 mappings(LPC), get_type_info(E), structp(E), to_mapping(E),
226 to_struct(E), struct_info(E), baseof(E)