blob: e45f46468501f6d74f864db605a7771d308546c5 [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
Zesstra3085c662025-08-02 18:31:10 +020053 nested. This also means that in one program there must not be
54 two structs, inherited or not, with the same name. This does not
55 apply to structs declared as private.
MG Mud User88f12472016-06-24 23:31:02 +020056
57
58 To declare a struct without defining it, write:
59
60 struct Quux;
61
62 This notation is useful if you have two structs referencing
63 each other:
64
65 struct Quux;
66
67 struct Bar {
68 struct Quux quux;
69 };
70 struct Quux {
71 struct Bar bar;
72 };
73
74
75USAGE
76 To use a struct, its definition must be visible - either because it
77 is defined in the object compiled, or it has been inherited.
78 (Note: #include'ing structs does not what you think it does: in
79 LPC it constructs a new struct type whereever it is included).
80
81
Zesstra3085c662025-08-02 18:31:10 +020082 A variable to hold a specific or arbitrary struct is defined like
83 this:
MG Mud User88f12472016-06-24 23:31:02 +020084
85 struct Foo var;
Zesstra3085c662025-08-02 18:31:10 +020086 struct mixed var;
MG Mud User88f12472016-06-24 23:31:02 +020087
88 and similar for function arguments:
89
90 void fun (struct Foo arg)
Zesstra3085c662025-08-02 18:31:10 +020091 void fun (struct mixed arg)
MG Mud User88f12472016-06-24 23:31:02 +020092
93
94 Just writing 'struct Foo var' however does not _create_ a struct,
95 it just creates a variable capable of holding one. To assign a value
96 to the variable upon creation, assign it with a struct value, either
97 from another variable or from a literal struct:
98
99 struct Foo var = (<Foo>);
100
101
102 Literal structs are written using (<>) as delimiters:
103
104 (<Foo>)
105 creates an empty instance of struct Foo
106
107 (<Foo> 1, ({ 2 }), bar)
108 creates an instance of struct Foo, and assigns 1 to member
109 'one', ({ 2 }) to member 'two', and the content of variable
110 bar to member 'three'.
111
112 (<Foo> two: ({ 2 }) )
113 creates an instance of struct Foo which is all empty except
114 for member 'two' which is assigned the value ({ 2 }).
115
116 It is not possible to use both named and unnamed initializers
117 in the same literal.
118
119
Zesstracbd5f9b2020-08-11 21:08:39 +0200120 A struct member is accessed using the . and -> operators:
MG Mud User88f12472016-06-24 23:31:02 +0200121
122 struct Foo var = ...;
123
Zesstracbd5f9b2020-08-11 21:08:39 +0200124 var.one = 1;
MG Mud User88f12472016-06-24 23:31:02 +0200125 var->one = 1;
126
127
128 It is possible to compute struct lookups at runtime:
129
130 struct Foo bar = ...;
131 string member = "one";
132
Zesstracbd5f9b2020-08-11 21:08:39 +0200133 bar.(member) = 1; // Sets bar.one to 1
134 bar.(0) = 1; // Sets bar.one to 1
MG Mud User88f12472016-06-24 23:31:02 +0200135 bar->(member) = 1; // sets bar->one to 1
136 bar->(0) = 1; // sets bar->one to 1
137
138
Zesstracbd5f9b2020-08-11 21:08:39 +0200139 If the given member does not exist, the -> operator will return 0,
140 but the . operator will throw an error.
MG Mud User88f12472016-06-24 23:31:02 +0200141
142
143USAGE IN CLOSURES
144 The #'(< operator can be used in lambda closures to create a
145 struct; the type of the struct is given by the 'template'
146 struct passed as first argument. The content of the template
147 struct is irrelevant, so an empty struct suffices. For
148 example, to create an instance of struct Foo:
Zesstra7ea4a032019-11-26 20:11:40 +0100149
MG Mud User88f12472016-06-24 23:31:02 +0200150 ({ #'(<, (<Foo>), 1, ({ 2 }), (<Bar>) })
151
152 The order of the member values is the order in which they
153 appear in the struct definition.
154
155 To access a struct member in a lambda closure, use the #'->
156 operator with the name of the member as double-quoted symbol
157 or literal string:
158
159 ({ #'->, struct-expression, ''one })
160 ({ #'->, struct-expression, "one" })
161
162
163MISCELLANEOUS
164 Internally structs can be identified by the ID string
165 returned from get_type_info(). This string contains the name
166 of the struct, the name of the program its type was defined in,
167 and the ID number of the program. However, do not rely on
168 a particular format of this string!
169
170 Support for structs is signaled by the macro __LPC_STRUCTS__.
171
Zesstra7ea4a032019-11-26 20:11:40 +0100172 Though structs are tied to the program the are defined in,
173 re-compiling a program doesn't make the struct types
174 incompatible. Even if the newly compiled struct has a
175 different structure it will be accepted by routines that
176 expect the old struct definition. When members disappeared
177 in the new struct definition, read access to those members
178 will return 0, write access to vanished members however
179 will result in a runtime error.
MG Mud User88f12472016-06-24 23:31:02 +0200180
181
182EXAMPLES
183 Suppose we have two objects: a monster, and a monster
184 coordinate tracker, and we want to use a struct to store the
185 coordinate:
186
187 -- monster_coordinate.c --
188 struct Coordinate { int x; int y; };
189
190 -- monster_tracker.c --
191 inherit "monster_coordinate";
192
193 void track (struct Coordinate coord) { ... }
194
195 -- monster.c --
196 inherit "monster_coordinate";
197
198 int move (..) {
199 ...
200 "monster_tracker"->track( (<Coordinate> my_x, my_y) );
201 }
202
203 Note that using '#include "monster_coordinate.c"' instead of inherit
204 won't work. While the objects would compile, the first call to
205 track() would cause a runtime error of the type
206
207 Illegal type to struct->(): struct Coordinate (/monster.c #234),
208 expected struct Coordinate
209 (/monster_tracker.c #552)
210
211
212HISTORY
213 structs were fully implemented first in LDMud 3.3.246.
214 The implementation was revised in LDMud 3.3.344.
215 The reactivation of unchanged structs in object updates was
216 implemented in LDMud 3.3.417.
Zesstracbd5f9b2020-08-11 21:08:39 +0200217 In LDMud 3.6.2 the . operator for struct member access was introduced
218 and the -> operator changed into a relaxed access operation.
MG Mud User88f12472016-06-24 23:31:02 +0200219
220
221SEE ALSO
222 mappings(LPC), get_type_info(E), structp(E), to_mapping(E),
223 to_struct(E), struct_info(E), baseof(E)