blob: a53029a3abd50294022748053954c9292ed3746b [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
Zesstracbd5f9b2020-08-11 21:08:39 +0200116 A struct member is accessed using the . and -> operators:
MG Mud User88f12472016-06-24 23:31:02 +0200117
118 struct Foo var = ...;
119
Zesstracbd5f9b2020-08-11 21:08:39 +0200120 var.one = 1;
MG Mud User88f12472016-06-24 23:31:02 +0200121 var->one = 1;
122
123
124 It is possible to compute struct lookups at runtime:
125
126 struct Foo bar = ...;
127 string member = "one";
128
Zesstracbd5f9b2020-08-11 21:08:39 +0200129 bar.(member) = 1; // Sets bar.one to 1
130 bar.(0) = 1; // Sets bar.one to 1
MG Mud User88f12472016-06-24 23:31:02 +0200131 bar->(member) = 1; // sets bar->one to 1
132 bar->(0) = 1; // sets bar->one to 1
133
134
Zesstracbd5f9b2020-08-11 21:08:39 +0200135 If the given member does not exist, the -> operator will return 0,
136 but the . operator will throw an error.
MG Mud User88f12472016-06-24 23:31:02 +0200137
138
139USAGE IN CLOSURES
140 The #'(< operator can be used in lambda closures to create a
141 struct; the type of the struct is given by the 'template'
142 struct passed as first argument. The content of the template
143 struct is irrelevant, so an empty struct suffices. For
144 example, to create an instance of struct Foo:
Zesstra7ea4a032019-11-26 20:11:40 +0100145
MG Mud User88f12472016-06-24 23:31:02 +0200146 ({ #'(<, (<Foo>), 1, ({ 2 }), (<Bar>) })
147
148 The order of the member values is the order in which they
149 appear in the struct definition.
150
151 To access a struct member in a lambda closure, use the #'->
152 operator with the name of the member as double-quoted symbol
153 or literal string:
154
155 ({ #'->, struct-expression, ''one })
156 ({ #'->, struct-expression, "one" })
157
158
159MISCELLANEOUS
160 Internally structs can be identified by the ID string
161 returned from get_type_info(). This string contains the name
162 of the struct, the name of the program its type was defined in,
163 and the ID number of the program. However, do not rely on
164 a particular format of this string!
165
166 Support for structs is signaled by the macro __LPC_STRUCTS__.
167
Zesstra7ea4a032019-11-26 20:11:40 +0100168 Though structs are tied to the program the are defined in,
169 re-compiling a program doesn't make the struct types
170 incompatible. Even if the newly compiled struct has a
171 different structure it will be accepted by routines that
172 expect the old struct definition. When members disappeared
173 in the new struct definition, read access to those members
174 will return 0, write access to vanished members however
175 will result in a runtime error.
MG Mud User88f12472016-06-24 23:31:02 +0200176
177
178EXAMPLES
179 Suppose we have two objects: a monster, and a monster
180 coordinate tracker, and we want to use a struct to store the
181 coordinate:
182
183 -- monster_coordinate.c --
184 struct Coordinate { int x; int y; };
185
186 -- monster_tracker.c --
187 inherit "monster_coordinate";
188
189 void track (struct Coordinate coord) { ... }
190
191 -- monster.c --
192 inherit "monster_coordinate";
193
194 int move (..) {
195 ...
196 "monster_tracker"->track( (<Coordinate> my_x, my_y) );
197 }
198
199 Note that using '#include "monster_coordinate.c"' instead of inherit
200 won't work. While the objects would compile, the first call to
201 track() would cause a runtime error of the type
202
203 Illegal type to struct->(): struct Coordinate (/monster.c #234),
204 expected struct Coordinate
205 (/monster_tracker.c #552)
206
207
208HISTORY
209 structs were fully implemented first in LDMud 3.3.246.
210 The implementation was revised in LDMud 3.3.344.
211 The reactivation of unchanged structs in object updates was
212 implemented in LDMud 3.3.417.
Zesstracbd5f9b2020-08-11 21:08:39 +0200213 In LDMud 3.6.2 the . operator for struct member access was introduced
214 and the -> operator changed into a relaxed access operation.
MG Mud User88f12472016-06-24 23:31:02 +0200215
216
217SEE ALSO
218 mappings(LPC), get_type_info(E), structp(E), to_mapping(E),
219 to_struct(E), struct_info(E), baseof(E)