]> gitweb.factorcode.org Git - factor.git/blob - core/classes/tuple/tuple-docs.factor
improve help by linking to types directly.
[factor.git] / core / classes / tuple / tuple-docs.factor
1 USING: arrays assocs classes classes.tuple.private
2 compiler.units growable help.markup help.syntax kernel math
3 sbufs sequences slots strings vectors words ;
4 IN: classes.tuple
5
6 ARTICLE: "slot-read-only-declaration" "Read-only slots"
7 "By default, all slots are writable. If a slot is explicitly declared " { $link read-only } ", then no writer method is generated for the slot, and the only way to set it to a value other than its initial value is to construct an instance of the tuple with " { $link boa } ", passing the initial value for the read-only slot on the stack; the common idiom of calling " { $link new } " and then immediately filling in slot values with setter words will not work with read-only slots." ;
8
9 ARTICLE: "slot-class-declaration" "Slot class declarations"
10 "Class declaration is optional, and the default value is " { $link object } ", the class of all objects. If a more specific class is declared, then the object system maintains an invariant that the value of the slot must always be an instance of the class, even during construction. This invariant is enforced at a number of locations:"
11 { $list
12     { "Writer words (" { $link "accessors" } ") throw an error if the new value does not satisfy the class predicate." }
13     { "The " { $link new } " word fills in slots with their initial values; the (per-class) initial values are required to satisfy the class predicate." }
14     { "The " { $link boa } " word ensures that the values on the stack satisfy the class predicate." }
15     { { $link "mirrors" } " ensure that the value passed to " { $link set-at } " satisfies the class predicate." }
16     { "The " { $link slots>tuple } " and " { $link >tuple } " words ensure that the values in the sequence satisfy the correct class predicates." }
17     { { $link "tuple-redefinition" } " fills in new slots with initial values and ensures that changes to existing declarations result in incompatible values being replaced with the initial value of their respective slots." }
18 }
19 { $subsections "slot-class-coercion" } ;
20
21 ARTICLE: "slot-class-coercion" "Coercive slot declarations"
22 "If the class of a slot is declared to be one of " { $link fixnum } " or " { $link float } ", then rather than testing values with the class predicate, writer words coerce values to the relevant type with " { $link >fixnum } " or " { $link >float } ". This may still result in error, but permits a wider range of values than a class predicate test. It also results in a possible loss of precision; for example, storing a large integer into a " { $link fixnum } " slot will silently overflow and discard high bits, and storing a ratio into a " { $link float } " slot may lose precision if the ratio is one which cannot be represented exactly with floating-point."
23 $nl
24 "This feature is mostly intended as an optimization for low-level code designed to avoid integer overflow, or where floating point precision is sufficient. Most code needs to work transparently with large integers, and thus should avoid the coercion behavior by using " { $link integer } " and " { $link real } " in place of " { $link fixnum } " and " { $link float } "." ;
25
26 ARTICLE: "tuple-declarations" "Tuple slot declarations"
27 "The slot specifier syntax of the " { $link POSTPONE: TUPLE: } " parsing word understands the following slot attributes:"
28 { $list
29     "class declaration: values must satisfy the class predicate"
30     { "whether a slot is read only or not (" { $link read-only } ")" }
31     { "an initial value (" { $link initial: } ")" }
32 }
33 { $subsections
34     "slot-read-only-declaration"
35     "slot-class-declaration"
36     "slot-initial-values"
37 } ;
38
39 ARTICLE: "parametrized-constructors" "Parameterized constructors"
40 "A " { $emphasis "parametrized constructor" } " is a word which directly or indirectly calls " { $link new } " or " { $link boa } ", but instead of passing a literal class symbol, it takes the class symbol as an input from the stack."
41 $nl
42 "Parametrized constructors are useful in many situations, in particular with subclassing. For example, consider the following code:"
43 { $code
44     "TUPLE: vehicle max-speed occupants ;"
45     ""
46     ": add-occupant ( person vehicle -- ) occupants>> push ;"
47     ""
48     "TUPLE: car < vehicle engine ;"
49     ": <car> ( max-speed engine -- car )"
50     "    car new"
51     "        V{ } clone >>occupants"
52     "        swap >>engine"
53     "        swap >>max-speed ;"
54     ""
55     "TUPLE: aeroplane < vehicle max-altitude ;"
56     ": <aeroplane> ( max-speed max-altitude -- aeroplane )"
57     "    aeroplane new"
58     "        V{ } clone >>occupants"
59     "        swap >>max-altitude"
60     "        swap >>max-speed ;"
61 }
62 "The two constructors depend on the implementation of " { $snippet "vehicle" } " because they are responsible for initializing the " { $snippet "occupants" } " slot to an empty vector. If this slot is changed to contain a hashtable instead, there will be two places instead of one. A better approach is to use a parametrized constructor for vehicles:"
63 { $code
64     "TUPLE: vehicle max-speed occupants ;"
65     ""
66     ": add-occupant ( person vehicle -- ) occupants>> push ;"
67     ""
68     ": new-vehicle ( class -- vehicle )"
69     "    new"
70     "        V{ } clone >>occupants ;"
71     ""
72     "TUPLE: car < vehicle engine ;"
73     ": <car> ( max-speed engine -- car )"
74     "    car new-vehicle"
75     "        swap >>engine"
76     "        swap >>max-speed ;"
77     ""
78     "TUPLE: aeroplane < vehicle max-altitude ;"
79     ": <aeroplane> ( max-speed max-altitude -- aeroplane )"
80     "    aeroplane new-vehicle"
81     "        swap >>max-altitude"
82     "        swap >>max-speed ;"
83 }
84 "The naming convention for parametrized constructors is " { $snippet "new-" { $emphasis "class" } } "." ;
85
86 ARTICLE: "tuple-constructors" "Tuple constructors"
87 "Tuples are created by calling one of two constructor primitives:"
88 { $subsections
89     new
90     boa
91 }
92 "A shortcut for defining BOA constructors:"
93 { $subsections POSTPONE: C: }
94 "By convention, construction logic is encapsulated in a word named after the tuple class surrounded in angle brackets; for example, the constructor word for a " { $snippet "point" } " class might be named " { $snippet "<point>" } "."
95 $nl
96 "Constructors play a part in enforcing the invariant that slot values must always match slot declarations. The " { $link new } " word fills in the tuple with initial values, and " { $link boa } " ensures that the values on the stack match the corresponding slot declarations. See " { $link "tuple-declarations" } "."
97 $nl
98 "All tuple construction should be done through constructor words, and construction primitives should be encapsulated and never called outside of the vocabulary where the class is defined, because this encourages looser coupling. For example, a constructor word could be changed to use memoization instead of always constructing a new instance, or it could be changed to construct a different class, without breaking callers."
99 $nl
100 "Examples of constructors:"
101 { $code
102     "TUPLE: color"
103     "{ red integer }"
104     "{ green integer }"
105     "{ blue integer }"
106     "{ alpha integer initial: 1 } ;"
107     ""
108     "! The following two are equivalent"
109     "C: <rgba> color"
110     ": <rgba> color boa ;"
111     ""
112     "! We can define constructors which call other constructors"
113     ": <rgb> ( r g b -- color ) 1 <rgba> ;"
114     ""
115     "! The following two are equivalent; note the initial value"
116     ": <color> ( -- color ) color new ;"
117     ": <color> ( -- color ) 0 0 0 1 <rgba> ;"
118     "! Run-time error"
119     "\"not a number\" 2 3 4 color boa"
120 }
121 { $subsections "parametrized-constructors" } ;
122
123 ARTICLE: "tuple-inheritance-example" "Tuple subclassing example"
124 "Rectangles, parallelograms and circles are all shapes. We support two operations on shapes:"
125 { $list
126     "Computing the area"
127     "Computing the perimeter"
128 }
129 "Rectangles and parallelograms use the same algorithm for computing the area, whereas they use different algorithms for computing perimeter. Also, rectangles and parallelograms both have " { $snippet "width" } " and " { $snippet "height" } " slots. We can exploit this with subclassing:"
130 { $code
131     "USING: accessors kernel math math.constants math.functions ;"
132     "GENERIC: area ( shape -- n )"
133     "GENERIC: perimeter ( shape -- n )"
134     ""
135     "TUPLE: shape ;"
136     ""
137     "TUPLE: circle < shape radius ;"
138     "M: circle area radius>> sq pi * ;"
139     "M: circle perimeter radius>> 2 * pi * ;"
140     ""
141     "TUPLE: quad < shape width height ;"
142     "M: quad area [ width>> ] [ height>> ] bi * ;"
143     ""
144     "TUPLE: rectangle < quad ;"
145     "M: rectangle perimeter [ width>> 2 * ] [ height>> 2 * ] bi + ;"
146     ""
147     ": hypot ( a b -- c ) [ sq ] bi@ + sqrt ;"
148     ""
149     "TUPLE: parallelogram < quad skew ;"
150     "M: parallelogram perimeter"
151     "    [ width>> 2 * ] [ [ height>> ] [ skew>> ] bi hypot 2 * ] bi + ;"
152 } ;
153
154 ARTICLE: "tuple-inheritance-anti-example" "When not to use tuple subclassing"
155 "Tuple subclassing should only be used for " { $emphasis "is-a" } " relationships; for example, a car " { $emphasis "is a" } " vehicle, and a circle " { $emphasis "is a" } " shape."
156 { $heading "Anti-pattern #1: subclassing for has-a" }
157 "Subclassing should not be used for " { $emphasis "has-a" } " relationships. For example, if a shape " { $emphasis "has a" } " color, then " { $snippet "shape" } " should not subclass " { $snippet "color" } ". Using tuple subclassing in inappropriate situations leads to code which is more brittle and less flexible than it should be."
158 $nl
159 "For example, suppose that " { $snippet "shape" } " inherits from " { $snippet "color" } ":"
160 { $code
161     "TUPLE: color r g b ;"
162     "TUPLE: shape < color ... ;"
163 }
164 "Now, the implementation of " { $snippet "shape" } " depends on a specific representation of colors as RGB colors. If a new generic color protocol is devised which also allows HSB and YUV colors to be used, the shape class will not be able to take advantage of them without changes. A better approach is to store the color in a slot:"
165 { $code
166     "TUPLE: rgb-color r g b ;"
167     "TUPLE: hsv-color h s v ;"
168     "..."
169     "TUPLE: shape color ... ;"
170 }
171 "The " { $vocab-link "delegate" } " library provides a language abstraction for expressing has-a relationships."
172 { $heading "Anti-pattern #2: subclassing for implementation sharing only" }
173 "Tuple subclassing purely for sharing implementations of methods is not a good idea either. If a class " { $snippet "A" } " is a subclass of a class " { $snippet "B" } ", then instances of " { $snippet "A" } " should be usable anywhere that an instance of " { $snippet "B" } " is. If this property does not hold, then subclassing should not be used."
174 $nl
175 "There are two alternatives which are preferred to subclassing in this case. The first is " { $link "mixins" } "."
176 $nl
177 "The second is to use ad-hoc slot polymorphism. If two classes define a slot with the same name, then code which uses " { $link "accessors" } " can operate on instances of both objects, assuming the values stored in that slot implement a common protocol. This allows code to be shared without creating contrived relationships between classes."
178 { $heading "Anti-pattern #3: subclassing to override a method definition" }
179 "While method overriding is a very powerful tool, improper use can cause tight coupling of code and lead to difficulty in testing and refactoring. Subclassing should not be used as a means of “monkey patching” methods to fix bugs and add features. Only subclass from classes which were designed to be inherited from, and when writing classes of your own which are intended to be subclassed, clearly document what subclasses may and may not do. This includes construction policy; document whether subclasses should use " { $link new } ", " { $link boa } ", or a custom parametrized constructor."
180 { $see-also "parametrized-constructors" } ;
181
182 ARTICLE: "tuple-subclassing" "Tuple subclassing"
183 "Tuple subclassing can be used to express natural relationships between classes at the language level. For example, every car " { $emphasis "is a" } " vehicle, so if the " { $snippet "car" } " class subclasses the " { $snippet "vehicle" } " class, it can " { $emphasis "inherit" } " the slots and methods of " { $snippet "vehicle" } "."
184 $nl
185 "To define one tuple class as a subclass of another, use the optional superclass parameter to " { $link POSTPONE: TUPLE: } ":"
186 { $code
187     "TUPLE: subclass < superclass ... ;"
188 }
189 { $subsections
190     "tuple-inheritance-example"
191     "tuple-inheritance-anti-example"
192 }
193 "Declaring a tuple class final prohibits other classes from subclassing it:"
194 { $subsections POSTPONE: final }
195 { $see-also "call-next-method" "parametrized-constructors" "unions" "mixins" } ;
196
197 ARTICLE: "tuple-introspection" "Tuple introspection"
198 "In addition to the slot reader and writer words which " { $link POSTPONE: TUPLE: } " defines for every tuple class, it is possible to construct and take apart entire tuples in a generic way."
199 { $subsections
200     >tuple
201     tuple>array
202     tuple-slots
203 }
204 "Tuples can be compared for slot equality even if the tuple class overrides " { $link equal? } ":"
205 { $subsections tuple= }
206 "Tuple classes can also be defined at run time:"
207 { $subsections define-tuple-class }
208 { $see-also "slots" "mirrors" } ;
209
210 ARTICLE: "tuple-examples" "Tuple examples"
211 "An example:"
212 { $code "TUPLE: employee name position salary ;" }
213 "This defines a class word named " { $snippet "employee" } ", a predicate " { $snippet "employee?" } ", and the following slot accessors:"
214 { $table
215     { "Reader" "Writer" "Setter" "Changer" }
216     { { $snippet "name>>" } { $snippet "name<<" } { $snippet ">>name" } { $snippet "change-name" } }
217     { { $snippet "position>>" } { $snippet "position<<" } { $snippet ">>position" } { $snippet "change-position" } }
218     { { $snippet "salary>>" } { $snippet "salary<<" } { $snippet ">>salary" } { $snippet "change-salary" } }
219 }
220 "We can define a constructor which makes an empty employee:"
221 { $code
222     ": <employee> ( -- employee )"
223     "    employee new ;"
224 }
225 "Or we may wish the default constructor to always give employees a starting salary:"
226 { $code
227     ": <employee> ( -- employee )"
228     "    employee new"
229     "        40000 >>salary ;"
230 }
231 "We can define more refined constructors:"
232 { $code
233     ": <manager> ( -- manager )"
234     "    <employee> \"project manager\" >>position ;" }
235 "An alternative strategy is to define the most general BOA constructor first:"
236 { $code
237     ": <employee> ( name position -- employee )"
238     "    40000 employee boa ;"
239 }
240 "Now we can define more specific constructors:"
241 { $code
242     ": <manager> ( name -- employee )"
243     "    \"manager\" <employee> ;" }
244 "An example using reader words:"
245 { $code
246     "TUPLE: check to amount number ;"
247     ""
248     "SYMBOL: checks"
249     ""
250     ": <check> ( to amount -- check )"
251     "    checks counter check boa ;"
252     ""
253     ": biweekly-paycheck ( employee -- check )"
254     "    [ name>> ] [ salary>> 26 / ] bi <check> ;"
255 }
256 "An example of using a changer:"
257 { $code
258     ": positions ( -- seq )"
259     "    {"
260     "        \"junior programmer\""
261     "        \"senior programmer\""
262     "        \"project manager\""
263     "        \"department manager\""
264     "        \"executive\""
265     "        \"CTO\""
266     "        \"CEO\""
267     "        \"enterprise Java world dictator\""
268     "    } ;"
269     ""
270     ": next-position ( role -- newrole )"
271     "    positions [ index 1 + ] keep nth ;"
272     ""
273     ": promote ( employee -- employee )"
274     "    [ 1.2 * ] change-salary"
275     "    [ next-position ] change-position ;"
276 }
277 "An example using subclassing can be found in " { $link "tuple-inheritance-example" } "." ;
278
279 ARTICLE: "tuple-redefinition" "Tuple redefinition"
280 "In the following, the " { $emphasis "direct slots" } " of a tuple class refers to the slot names specified in the " { $link POSTPONE: TUPLE: } " form defining the tuple class, and the " { $emphasis "effective slots" } " refers to the concatenation of the direct slots together with slots defined on superclasses."
281 $nl
282 "When the " { $emphasis "effective slots" } " of a tuple class change, all instances of the class, including subclasses, are updated."
283 $nl
284 "There are three ways in which the list of effective slots may change:"
285 { $list
286     "Adding or removing direct slots of the class"
287     "Adding or removing direct slots of a superclass of the class"
288     "Changing the inheritance hierarchy by changing the superclass of a class"
289     "Declarations changing on existing slots"
290 }
291 "In all cases, the new effective slots are compared with the old effective slots, and each instance is updated as follows:"
292 { $list
293     "If any slots were removed, the values are removed from the instance and are lost forever."
294     "If any slots were added, the instance gains these slots, all set to their initial values."
295     "If any slots are permuted, their values in instances do not change; only the layout of the instance changes in memory."
296     "If the slot declaration of an existing slot changes, existing values are checked to see if they are still an instance of the required class. Any which are not are replaced by the initial value of that slot."
297     "If the number or order of effective slots changes, any BOA constructors are recompiled."
298 }
299 "Note that if a slot is moved from a class to its superclass (or vice versa) in the same compilation unit, the value of the slot is preserved in existing instances, because tuple instance update always runs at the end of a compilation unit. However, if it is removed in one compilation unit and added in another, the value in existing instances is lost." ;
300
301 ARTICLE: "protocol-slots" "Protocol slots"
302 "A " { $emphasis "protocol slot" } " is one which is assumed to exist by the implementation of a class, without being defined on the class itself. The burden is on subclasses (or mixin instances) to provide this slot."
303 $nl
304 "Protocol slots are defined using a parsing word:"
305 { $subsections POSTPONE: SLOT: }
306 "Protocol slots are used where the implementation of a superclass needs to assume that each subclass defines certain slots, however the slots of each subclass are potentially declared with different class specializers, thus preventing the slots from being defined in the superclass."
307 $nl
308 "For example, the " { $link growable } " mixin provides an implementation of the sequence protocol which wraps an underlying sequence, resizing it as necessary when elements are added beyond the length of the sequence. It assumes that the concrete mixin instances define two slots, " { $snippet "length" } " and " { $snippet "underlying" } ". These slots are defined as protocol slots: " { $snippet "SLOT: length" } " and " { $snippet "SLOT: underlying" } ". "
309 "An alternate approach would be to define " { $link growable } " as a tuple class with these two slots, and have other classes subclass it as required. However, this rules out subclasses defining these slots with custom type declarations."
310 $nl
311 "For example, compare the definitions of the " { $link sbuf } " class,"
312 { $code
313     "TUPLE: sbuf"
314     "{ underlying string }"
315     "{ length array-capacity } ;"
316     ""
317     "INSTANCE: sbuf growable"
318 }
319 "with that of the " { $link vector } " class:"
320 { $code
321     "TUPLE: vector"
322     "{ underlying array }"
323     "{ length array-capacity } ;"
324     ""
325     "INSTANCE: vector growable"
326 } ;
327
328 ARTICLE: "tuples" "Tuples"
329 "Tuples are user-defined classes composed of named slots. They are the central data type of Factor's object system."
330 { $subsections "tuple-examples" }
331 "A parsing word defines tuple classes:"
332 { $subsections POSTPONE: TUPLE: }
333 "For each tuple class, several words are defined, the class word, a class predicate, and accessor words for each slot."
334 $nl
335 "The class word is used for defining methods on the tuple class; it has the same name as the tuple class. The predicate is named " { $snippet { $emphasis "name" } "?" } ". Initially, no specific words are defined for constructing new instances of the tuple. Constructors must be defined explicitly, and tuple slots are accessed via automatically-generated accessor words."
336 { $subsections
337     "accessors"
338     "tuple-constructors"
339     "tuple-subclassing"
340     "tuple-declarations"
341     "protocol-slots"
342     "tuple-introspection"
343 }
344 "Tuple classes can be redefined; this updates existing instances:"
345 { $subsections "tuple-redefinition" }
346 "Tuple literal syntax is documented in " { $link "syntax-tuples" } "." ;
347
348 ABOUT: "tuples"
349
350 HELP: tuple-class
351 { $class-description "The class of tuple class words." }
352 { $examples { $example "USING: classes.tuple prettyprint ;" "IN: scratchpad" "TUPLE: name title first last ;" "name tuple-class? ." "t" } } ;
353
354 HELP: tuple=
355 { $values { "tuple1" tuple } { "tuple2" tuple } { "?" boolean } }
356 { $description "Checks if two tuples have equal slot values. This is the default behavior of " { $link = } " on tuples, unless the tuple class subclasses " { $link identity-tuple } " or implements a method on " { $link equal? } ". In cases where equality has been redefined, this word can be used to get the default semantics if needed." } ;
357
358 HELP: tuple
359 { $class-description "The class of tuples. This class is further partitioned into disjoint subclasses; each tuple shape defined by " { $link POSTPONE: TUPLE: } " is a new class."
360 $nl
361 "Tuple classes have additional word properties:"
362 { $list
363     { { $snippet "\"predicate\"" } " - a quotation which tests if the top of the stack is an instance of this tuple class" }
364     { { $snippet "\"slots\"" } " - a sequence of " { $link slot-spec } " instances" }
365     { { $snippet "\"layout\"" } " - an array with the tuple size and superclasses encoded in a format amneable to fast method dispatch" }
366 } } ;
367
368 HELP: define-tuple-predicate
369 { $values { "class" tuple-class } }
370 { $description "Defines a predicate word that tests if the top of the stack is an instance of " { $snippet "class" } ". This will only work if " { $snippet "class" } " is a tuple class." }
371 $low-level-note ;
372
373 HELP: redefine-tuple-class
374 { $values { "class" class } { "superclass" class } { "slots" "a sequence of strings" } }
375 { $description "If the new slot layout differs from the existing one, updates all existing instances of this tuple class, and forgets any slot accessor words which are no longer needed."
376 $nl
377 "If the class is not a tuple class word, this word does nothing." }
378 $low-level-note ;
379
380 HELP: tuple-slots
381 { $values { "tuple" tuple } { "seq" sequence } }
382 { $description "Pushes a sequence of tuple slot values, not including the tuple class word." } ;
383
384 { tuple-slots tuple>array } related-words
385
386 HELP: define-tuple-slots
387 { $values { "class" tuple-class } }
388 { $description "Defines slot accessor and mutator words for the tuple." }
389 $low-level-note ;
390
391 HELP: check-tuple
392 { $values { "class" class } }
393 { $description "Throws a " { $link check-tuple } " error if " { $snippet "word" } " is not a tuple class word." }
394 { $error-description "Thrown if " { $link POSTPONE: C: } " is called with a word which does not name a tuple class." } ;
395
396 HELP: define-tuple-class
397 { $values { "class" word } { "superclass" class } { "slots" "a sequence of strings" } }
398 { $description "Defines a tuple class inheriting from " { $snippet "superclass" } " with slots named by " { $snippet "slots" } ". This is the run time equivalent of " { $link POSTPONE: TUPLE: } "." }
399 { $notes "This word must be called from inside " { $link with-compilation-unit } "." }
400 { $side-effects "class" } ;
401
402 { tuple-class define-tuple-class POSTPONE: TUPLE: } related-words
403
404 HELP: >tuple
405 { $values { "seq" sequence } { "tuple" tuple } }
406 { $description "Creates a tuple with slot values taken from a sequence. The first element of the sequence must be a tuple class word and the remainder the declared slots."
407 $nl
408 "If the sequence has too few elements, the remaining slots in the tuple are set to their initial values." }
409 { $errors "Throws an error if one of the following occurs:"
410     { $list
411         "the first element of the sequence is not a tuple class word"
412         "the values in the sequence do not satisfy the slot class predicates"
413         "the sequence is too long"
414     }
415 } ;
416
417 HELP: tuple>array
418 { $values { "tuple" tuple } { "array" array } }
419 { $description "Outputs an array having the tuple's slots as elements. The first element is the tuple class word and remainder are declared slots." } ;
420
421 HELP: <tuple>
422 { $values { "layout" "a tuple layout array" } { "tuple" tuple } }
423 { $description "Low-level tuple constructor. User code should never call this directly, and instead use " { $link new } "." } ;
424
425 HELP: <tuple-boa>
426 { $values { "slots..." "values" } { "layout" "a tuple layout array" } { "tuple" tuple } }
427 { $description "Low-level tuple constructor. User code should never call this directly, and instead use " { $link boa } "." } ;
428
429 HELP: new
430 { $values { "class" tuple-class } { "tuple" tuple } }
431 { $description "Creates a new instance of " { $snippet "class" } " with all slots set to their initial values (see " { $link "tuple-declarations" } ")." }
432 { $examples
433     { $example
434         "USING: kernel prettyprint ;"
435         "IN: scratchpad"
436         "TUPLE: employee number name department ;"
437         "employee new ."
438         "T{ employee }"
439     }
440 } ;
441
442 HELP: boa
443 { $values { "slots..." "slot values" } { "class" tuple-class } { "tuple" tuple } }
444 { $description "Creates a new instance of " { $snippet "class" } " and fill in the slots from the stack, with the top-most stack element being stored in the right-most slot." }
445 { $notes "The name " { $snippet "boa" } " is shorthand for “by order of arguments”, and “BOA constructor” is a pun on “boa constrictor”." }
446 { $errors "Throws an error if the slot values do not match class declarations on slots (see " { $link "tuple-declarations" } ")." } ;
447
448 HELP: bad-superclass
449 { $error-description "Thrown if an attempt is made to subclass a class that is not a tuple class, or a tuple class declared " { $link POSTPONE: final } "." } ;
450
451 HELP: offset-of-slot
452 { $values { "name" string } { "tuple" tuple } { "n" integer } }
453 { $description "Returns the offset of a tuple slot accessed by " { $snippet "name" } "." } ;
454
455 HELP: get-slot-named
456 { $values { "name" string } { "tuple" tuple } { "value" object } }
457 { $description "Returns the " { $snippet "value" } " stored in a tuple slot accessed by " { $snippet "name" } "." } ;
458
459 HELP: set-slot-named
460 { $values { "value" object } { "name" string } { "tuple" tuple } }
461 { $description "Stores the " { $snippet "value" } " into a tuple slot accessed by " { $snippet "name" } "." } ;
462
463 HELP: set-slots
464 { $values { "assoc" assoc } { "tuple" tuple } }
465 { $description "For each " { $snippet "{ key value }" } " pair in " { $snippet "assoc" } ", sets the " { $snippet "key" } " slot in " { $snippet "obj" } " to " { $snippet "value" } "." } ;
466
467 HELP: from-slots
468 { $values { "assoc" assoc } { "class" tuple-class } { "tuple" tuple } }
469 { $description "Creates a new instance of " { $snippet "class" } " with slot values specified by " { $snippet "assoc" } "." } ;