]> gitweb.factorcode.org Git - factor.git/blob - core/kernel/kernel-docs.factor
Create basis vocab root
[factor.git] / core / kernel / kernel-docs.factor
1 USING: generic help.markup help.syntax math memory
2 namespaces sequences kernel.private layouts classes
3 kernel.private vectors combinators quotations strings words
4 assocs arrays math.order ;
5 IN: kernel
6
7 ARTICLE: "shuffle-words" "Shuffle words"
8 "Shuffle words rearrange items at the top of the data stack. They control the flow of data between words that perform actions."
9 $nl
10 "The " { $link "cleave-combinators" } " and " { $link "spread-combinators" } " are closely related to shuffle words and should be used instead where possible because they can result in clearer code; also, see the advice in " { $link "cookbook-philosophy" } "."
11 $nl
12 "Removing stack elements:"
13 { $subsection drop }
14 { $subsection 2drop }
15 { $subsection 3drop }
16 { $subsection nip }
17 { $subsection 2nip }
18 "Duplicating stack elements:"
19 { $subsection dup }
20 { $subsection 2dup }
21 { $subsection 3dup }
22 { $subsection dupd }
23 { $subsection over }
24 { $subsection 2over }
25 { $subsection pick }
26 { $subsection tuck }
27 "Permuting stack elements:"
28 { $subsection swap }
29 { $subsection swapd }
30 { $subsection rot }
31 { $subsection -rot }
32 { $subsection spin }
33 { $subsection roll }
34 { $subsection -roll }
35 "Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using the following two words:"
36 { $subsection >r }
37 { $subsection r> }
38 "The top of the data stack is ``hidden'' between " { $link >r } " and " { $link r> } ":"
39 { $example "1 2 3 >r .s r>" "1\n2" }
40 "Words must not leave objects on the retain stack, nor expect values to be there on entry. The retain stack is for local storage within a word only, and occurrences of " { $link >r } " and " { $link r> } " must be balanced inside a single quotation. One exception is the following trick involving " { $link if } "; values may be pushed on the retain stack before the condition value is computed, as long as both branches of the " { $link if } " pop the values off the retain stack before returning:"
41 { $code
42     ": foo ( m ? n -- m+n/n )"
43     "    >r [ r> + ] [ drop r> ] if ; ! This is OK"
44 } ;
45
46 ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
47 "Cleave combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to cleave combinators are discussed in the documentation for " { $link bi } ", " { $link 2bi } ", " { $link 3bi } ", " { $link tri } ", " { $link 2tri } " and " { $link 3tri } "."
48 $nl
49 "Certain shuffle words can also be expressed in terms of the cleave combinators. Internalizing such identities can help with understanding and writing code using cleave combinators:"
50 { $code
51     ": keep  [ ] bi ;"
52     ": 2keep [ ] 2bi ;"
53     ": 3keep [ ] 3bi ;"
54     ""
55     ": dup   [ ] [ ] bi ;"
56     ": 2dup  [ ] [ ] 2bi ;"
57     ": 3dup  [ ] [ ] 3bi ;"
58     ""
59     ": tuck  [ nip ] [ ] 2bi ;"
60     ": swap  [ nip ] [ drop ] 2bi ;"
61     ""
62     ": over  [ ] [ drop ] 2bi ;"
63     ": pick  [ ] [ 2drop ] 3bi ;"
64     ": 2over [ ] [ drop ] 3bi ;"
65 } ;
66
67 ARTICLE: "cleave-combinators" "Cleave combinators"
68 "The cleave combinators apply multiple quotations to a single value."
69 $nl
70 "Two quotations:"
71 { $subsection bi }
72 { $subsection 2bi }
73 { $subsection 3bi }
74 "Three quotations:"
75 { $subsection tri }
76 { $subsection 2tri }
77 { $subsection 3tri }
78 "Technically, the cleave combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on the top of the stack can be written in one of two ways:"
79 { $code
80     "! First alternative; uses keep"
81     "[ 1 + ] keep"
82     "[ 1 - ] keep"
83     "2 *"
84     "! Second alternative: uses tri"
85     "[ 1 + ]"
86     "[ 1 - ]"
87     "[ 2 * ] tri"
88 }
89 "The latter is more aesthetically pleasing than the former."
90 $nl
91 "A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
92 { $subsection "cleave-shuffle-equivalence" } ;
93
94 ARTICLE: "spread-shuffle-equivalence" "Expressing shuffle words with spread combinators"
95 "Spread combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to spread combinators are discussed in the documentation for " { $link bi* } ", " { $link 2bi* } ", and " { $link tri* } "."
96 $nl
97 "Certain shuffle words can also be expressed in terms of the spread combinators. Internalizing such identities can help with understanding and writing code using spread combinators:"
98 { $code
99     ": dip   [ ] bi* ;"
100     ": 2dip  [ ] [ ] tri* ;"
101     ""
102     ": slip  [ call ] [ ] bi* ;"
103     ": 2slip [ call ] [ ] [ ] tri* ;"
104     ""
105     ": nip   [ drop ] [ ] bi* ;"
106     ": 2nip  [ drop ] [ drop ] [ ] tri* ;"
107     ""
108     ": rot"
109     "    [ [ drop ] [      ] [ drop ] tri* ]"
110     "    [ [ drop ] [ drop ] [      ] tri* ]"
111     "    [ [      ] [ drop ] [ drop ] tri* ]"
112     "    3tri ;"
113     ""
114     ": -rot"
115     "    [ [ drop ] [ drop ] [      ] tri* ]"
116     "    [ [      ] [ drop ] [ drop ] tri* ]"
117     "    [ [ drop ] [      ] [ drop ] tri* ]"
118     "    3tri ;"
119     ""
120     ": spin"
121     "    [ [ drop ] [ drop ] [      ] tri* ]"
122     "    [ [ drop ] [      ] [ drop ] tri* ]"
123     "    [ [      ] [ drop ] [ drop ] tri* ]"
124     "    3tri ;"
125 } ;
126
127 ARTICLE: "spread-combinators" "Spread combinators"
128 "The spread combinators apply multiple quotations to multiple values. The " { $snippet "*" } " suffix signifies spreading."
129 $nl
130 "Two quotations:"
131 { $subsection bi* }
132 { $subsection 2bi* }
133 "Three quotations:"
134 { $subsection tri* }
135 "Technically, the spread combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on three related values can be written in one of two ways:"
136 { $code
137     "! First alternative; uses retain stack explicitly"
138     ">r >r 1 +"
139     "r> 1 -"
140     "r> 2 *"
141     "! Second alternative: uses tri*"
142     "[ 1 + ]"
143     "[ 1 - ]"
144     "[ 2 * ] tri*"
145 }
146
147 $nl
148 "A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
149 { $subsection "spread-shuffle-equivalence" } ;
150
151 ARTICLE: "apply-combinators" "Apply combinators"
152 "The apply combinators apply a single quotation to multiple values. The " { $snippet "@" } " suffix signifies application."
153 $nl
154 "Two quotations:"
155 { $subsection bi@ }
156 { $subsection 2bi@ }
157 "Three quotations:"
158 { $subsection tri@ }
159 "A pair of utility words built from " { $link bi@ } ":"
160 { $subsection both? }
161 { $subsection either? } ;
162
163 ARTICLE: "slip-keep-combinators" "The slip and keep combinators"
164 "The slip combinators invoke a quotation further down on the stack. They are most useful for implementing other combinators:"
165 { $subsection slip }
166 { $subsection 2slip }
167 { $subsection 3slip }
168 "The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
169 { $subsection dip }
170 { $subsection 2dip }
171 "The keep combinators invoke a quotation which takes a number of values off the stack, and then they restore those values:"
172 { $subsection keep }
173 { $subsection 2keep }
174 { $subsection 3keep } ;
175
176 ARTICLE: "compositional-combinators" "Compositional combinators"
177 "Quotations can be composed using efficient quotation-specific operations:"
178 { $subsection curry }
179 { $subsection 2curry }
180 { $subsection 3curry }
181 { $subsection with }
182 { $subsection compose }
183 { $subsection 3compose }
184 { $subsection prepose }
185 "Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } "." ;
186
187 ARTICLE: "implementing-combinators" "Implementing combinators"
188 "The following pair of words invoke words and quotations reflectively:"
189 { $subsection call }
190 { $subsection execute }
191 "These words are used to implement combinators. Note that combinator definitions must be followed by the " { $link POSTPONE: inline } " declaration in order to compile in the optimizing compiler; for example:"
192 { $code
193     ": keep ( x quot -- x )"
194     "    over >r call r> ; inline"
195 }
196 "Word inlining is documented in " { $link "declarations" } "." ;
197
198 ARTICLE: "booleans" "Booleans"
199 "In Factor, any object that is not " { $link f } " has a true value, and " { $link f } " has a false value. The " { $link t } " object is the canonical true value."
200 { $subsection f }
201 { $subsection t }
202 "The " { $link f } " object is the unique instance of the " { $link f } " class; the two are distinct objects. The latter is also a parsing word which adds the " { $link f } " object to the parse tree at parse time. To refer to the class itself you must use " { $link POSTPONE: POSTPONE: } " or " { $link POSTPONE: \ } " to prevent the parsing word from executing."
203 $nl
204 "Here is the " { $link f } " object:"
205 { $example "f ." "f" }
206 "Here is the " { $link f } " class:"
207 { $example "\\ f ." "POSTPONE: f" }
208 "They are not equal:"
209 { $example "f \\ f = ." "f" }
210 "Here is an array containing the " { $link f } " object:"
211 { $example "{ f } ." "{ f }" }
212 "Here is an array containing the " { $link f } " class:"
213 { $example "{ POSTPONE: f } ." "{ POSTPONE: f }" }
214 "The " { $link f } " object is an instance of the " { $link f } " class:"
215 { $example "f class ." "POSTPONE: f" }
216 "The " { $link f } " class is an instance of " { $link word } ":"
217 { $example "\\ f class ." "word" }
218 "On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
219 { $example "t \\ t eq? ." "t" }
220 "Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ;
221
222 ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic"
223 "Certain simple conditional forms can be expressed in a simpler manner using boolean logic."
224 $nl
225 "The following two lines are equivalent:"
226 { $code "[ drop f ] unless" "swap and" }
227 "The following two lines are equivalent:"
228 { $code "[ ] [ ] ?if" "swap or" }
229 "The following two lines are equivalent, where " { $snippet "L" } " is a literal:"
230 { $code "[ L ] unless*" "L or" } ;
231
232 ARTICLE: "conditionals" "Conditionals and logic"
233 "The basic conditionals:"
234 { $subsection if }
235 { $subsection when }
236 { $subsection unless }
237 "Forms abstracting a common stack shuffle pattern:"
238 { $subsection if* }
239 { $subsection when* }
240 { $subsection unless* }
241 "Another form abstracting a common stack shuffle pattern:"
242 { $subsection ?if }
243 "Sometimes instead of branching, you just need to pick one of two values:"
244 { $subsection ? }
245 "There are some logical operations on booleans:"
246 { $subsection >boolean }
247 { $subsection not }
248 { $subsection and }
249 { $subsection or }
250 { $subsection xor }
251 { $subsection "conditionals-boolean-equivalence" }
252 "See " { $link "combinators" } " for forms which abstract away common patterns involving multiple nested branches."
253 { $see-also "booleans" "bitwise-arithmetic" both? either? } ;
254
255 ARTICLE: "equality" "Equality"
256 "There are two distinct notions of ``sameness'' when it comes to objects. You can test if two references point to the same object (" { $emphasis "identity comparison" } "), or you can test if two objects are equal in a domain-specific sense, usually by being instances of the same class, and having equal slot values (" { $emphasis "value comparison" } "). Both notions of equality are equality relations in the mathematical sense."
257 $nl
258 "Identity comparison:"
259 { $subsection eq? }
260 "Value comparison:"
261 { $subsection = }
262 "Custom value comparison methods:"
263 { $subsection equal? }
264 "Utility class:"
265 { $subsection identity-tuple }
266 "An object can be cloned; the clone has distinct identity but equal value:"
267 { $subsection clone } ;
268
269 ARTICLE: "dataflow" "Data and control flow"
270 { $subsection "evaluator" }
271 { $subsection "words" }
272 { $subsection "effects" }
273 { $subsection "booleans" }
274 { $subsection "shuffle-words" }
275 "A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
276 { $subsection "cleave-combinators" }
277 { $subsection "spread-combinators" }
278 { $subsection "apply-combinators" }
279 { $subsection "slip-keep-combinators" }
280 { $subsection "conditionals" }
281 { $subsection "compositional-combinators" }
282 { $subsection "combinators" }
283 "Advanced topics:"
284 { $subsection "implementing-combinators" }
285 { $subsection "errors" }
286 { $subsection "continuations" } ;
287
288 ABOUT: "dataflow"
289
290 HELP: eq? ( obj1 obj2 -- ? )
291 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
292 { $description "Tests if two references point at the same object." } ;
293
294 HELP: drop  ( x -- )                 $shuffle ;
295 HELP: 2drop ( x y -- )               $shuffle ;
296 HELP: 3drop ( x y z -- )             $shuffle ;
297 HELP: dup   ( x -- x x )             $shuffle ;
298 HELP: 2dup  ( x y -- x y x y )       $shuffle ;
299 HELP: 3dup  ( x y z -- x y z x y z ) $shuffle ;
300 HELP: rot   ( x y z -- y z x )       $shuffle ;
301 HELP: -rot  ( x y z -- z x y )       $shuffle ;
302 HELP: dupd  ( x y -- x x y )         $shuffle ;
303 HELP: swapd ( x y z -- y x z )       $shuffle ;
304 HELP: nip   ( x y -- y )             $shuffle ;
305 HELP: 2nip  ( x y z -- z )           $shuffle ;
306 HELP: tuck  ( x y -- y x y )         $shuffle ;
307 HELP: over  ( x y -- x y x )         $shuffle ;
308 HELP: 2over                          $shuffle ;
309 HELP: pick  ( x y z -- x y z x )     $shuffle ;
310 HELP: swap  ( x y -- y x )           $shuffle ;
311 HELP: spin                           $shuffle ;
312 HELP: roll                           $shuffle ;
313 HELP: -roll                          $shuffle ;
314
315 HELP: >r ( x -- )
316 { $values { "x" object } } { $description "Moves the top of the data stack to the retain stack." } ;
317
318 HELP: r> ( -- x )
319 { $values { "x" object } } { $description "Moves the top of the retain stack to the data stack." } ;
320
321 HELP: datastack ( -- ds )
322 { $values { "ds" array } }
323 { $description "Outputs an array containing a copy of the data stack contents right before the call to this word, with the top of the stack at the end of the array." } ;
324
325 HELP: set-datastack ( ds -- )
326 { $values { "ds" array } }
327 { $description "Replaces the data stack contents with a copy of an array. The end of the array becomes the top of the stack." } ;
328
329 HELP: retainstack ( -- rs )
330 { $values { "rs" array } }
331 { $description "Outputs an array containing a copy of the retain stack contents right before the call to this word, with the top of the stack at the end of the array." } ;
332
333 HELP: set-retainstack ( rs -- )
334 { $values { "rs" array } }
335 { $description "Replaces the retain stack contents with a copy of an array. The end of the array becomes the top of the stack." } ;
336
337 HELP: callstack ( -- cs )
338 { $values { "cs" callstack } }
339 { $description "Outputs a copy of the call stack contents, with the top of the stack at the end of the vector. The stack frame of the caller word is " { $emphasis "not" } " included." } ;
340
341 HELP: set-callstack ( cs -- )
342 { $values { "cs" callstack } }
343 { $description "Replaces the call stack contents. The end of the vector becomes the top of the stack. Control flow is transferred immediately to the new call stack." } ;
344
345 HELP: clear
346 { $description "Clears the data stack." } ;
347
348 HELP: build
349 { $description "The current build number. Factor increments this number whenever a new boot image is created." } ;
350
351 HELP: hashcode*
352 { $values { "depth" integer } { "obj" object } { "code" fixnum } }
353 { $contract "Outputs the hashcode of an object. The hashcode operation must satisfy the following properties:"
354 { $list
355     { "If two objects are equal under " { $link = } ", they must have equal hashcodes." }
356     { "If the hashcode of an object depends on the values of its slots, the hashcode of the slots must be computed recursively by calling " { $link hashcode* } " with a " { $snippet "level" } " parameter decremented by one. This avoids excessive work while still computing well-distributed hashcodes. The " { $link recursive-hashcode } " combinator can help with implementing this logic," }
357     { "The hashcode should be a " { $link fixnum } ", however returning a " { $link bignum } " will not cause any problems other than potential performance degradation." }
358     { "The hashcode is only permitted to change between two invocations if the object or one of its slot values was mutated." }
359 }
360 "If mutable objects are used as hashtable keys, they must not be mutated in such a way that their hashcode changes. Doing so will violate bucket sorting invariants and result in undefined behavior. See " { $link "hashtables.keys" } " for details." } ;
361
362 HELP: hashcode
363 { $values { "obj" object } { "code" fixnum } }
364 { $description "Computes the hashcode of an object with a default hashing depth. See " { $link hashcode* } " for the hashcode contract." } ;
365
366 { hashcode hashcode* } related-words
367
368 HELP: =
369 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
370 { $description
371     "Tests if two objects are equal. If " { $snippet "obj1" } " and " { $snippet "obj2" } " point to the same object, outputs " { $link t } ". Otherwise, calls the " { $link equal? } " generic word."
372 } ;
373
374 HELP: equal?
375 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
376 { $contract
377     "Tests if two objects are equal."
378     $nl
379     "User code should call " { $link = } " instead; that word first tests the case where the objects are " { $link eq? } ", and so by extension, methods defined on " { $link equal? } " assume they are never called on " { $link eq? } " objects."
380     $nl
381     "Method definitions should ensure that this is an equality relation, modulo the assumption that the two objects are not " { $link eq? } ". That is, for any three non-" { $link eq? } " objects " { $snippet "a" } ", " { $snippet "b" } " and " { $snippet "c" } ", we must have:"
382     { $list
383         { { $snippet "a = b" } " implies " { $snippet "b = a" } }
384         { { $snippet "a = b" } " and " { $snippet "b = c" } " implies " { $snippet "a = c" } }
385     }
386     $nl
387     "If a class defines a custom equality comparison test, it should also define a compatible method for the " { $link hashcode* } " generic word."
388 } ;
389
390 HELP: identity-tuple
391 { $class-description "A class defining an " { $link equal? } " method which always returns f." }
392 { $examples
393     "To define a tuple class such that two instances are only equal if they are both the same instance, inherit from the " { $link identity-tuple } " class. This class defines a method on " { $link equal? } " which always returns " { $link f } ". Since " { $link = } " handles the case where the two objects are " { $link eq? } ", this method will never be called with two " { $link eq? } " objects, so such a definition is valid:"
394     { $code "TUPLE: foo < identity-tuple ;" }
395     "By calling " { $link = } " on instances of " { $snippet "foo" } " we get the results we expect:"
396     { $unchecked-example "T{ foo } dup = ." "t" }
397     { $unchecked-example "T{ foo } dup clone = ." "f" }
398 } ;
399
400 HELP: clone
401 { $values { "obj" object } { "cloned" "a new object" } }
402 { $contract "Outputs a new object equal to the given object. This is not guaranteed to actually copy the object; it does nothing with immutable objects, and does not copy words either. However, sequences and tuples can be cloned to obtain a shallow copy of the original." } ;
403
404 HELP: ?
405 { $values { "?" "a generalized boolean" } { "true" object } { "false" object } { "true/false" "one two input objects" } }
406 { $description "Chooses between two values depending on the boolean value of " { $snippet "cond" } "." } ;
407
408 HELP: >boolean
409 { $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
410 { $description "Convert a generalized boolean into a boolean. That is, " { $link f } " retains its value, whereas anything else becomes " { $link t } "." } ;
411
412 HELP: not
413 { $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
414 { $description "For " { $link f } " outputs " { $link t } " and for anything else outputs " { $link f } "." }
415 { $notes "This word implements boolean not, so applying it to integers will not yield useful results (all integers have a true value). Bitwise not is the " { $link bitnot } " word." } ;
416
417 HELP: and
418 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
419 { $description "If both inputs are true, outputs " { $snippet "obj2" } ". otherwise outputs " { $link f } "." }
420 { $notes "This word implements boolean and, so applying it to integers will not yield useful results (all integers have a true value). Bitwise and is the " { $link bitand } " word." }
421 { $examples
422     "Usually only the boolean value of the result is used, however you can also explicitly rely on the behavior that if both inputs are true, the second is output:"
423     { $example "USING: kernel prettyprint ;" "t f and ." "f" }
424     { $example "USING: kernel prettyprint ;" "t 7 and ." "7" }
425     { $example "USING: kernel prettyprint ;" "\"hi\" 12.0 and ." "12.0" }
426 } ;
427
428 HELP: or
429 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
430 { $description "If both inputs are false, outputs " { $link f } ". otherwise outputs the first of " { $snippet "obj1" } " and " { $snippet "obj2" } " which is true." }
431 { $notes "This word implements boolean inclusive or, so applying it to integers will not yield useful results (all integers have a true value). Bitwise inclusive or is the " { $link bitor } " word." }
432 { $examples
433     "Usually only the boolean value of the result is used, however you can also explicitly rely on the behavior that the result will be the first true input:"
434     { $example "USING: kernel prettyprint ;" "t f or ." "t" }
435     { $example "USING: kernel prettyprint ;" "\"hi\" 12.0 or ." "\"hi\"" }
436 } ;
437
438 HELP: xor
439 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
440 { $description "Tests if at exactly one object is not " { $link f } "." }
441 { $notes "This word implements boolean exclusive or, so applying it to integers will not yield useful results (all integers have a true value). Bitwise exclusive or is the " { $link bitxor } " word." } ;
442
443 HELP: both?
444 { $values { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
445 { $description "Tests if the quotation yields a true value when applied to both " { $snippet "x" } " and " { $snippet "y" } "." }
446 { $examples
447     { $example "USING: kernel math prettyprint ;" "3 5 [ odd? ] both? ." "t" }
448     { $example "USING: kernel math prettyprint ;" "12 7 [ even? ] both? ." "f" }
449 } ;
450
451 HELP: either?
452 { $values { "quot" "a quotation with stack effect " { $snippet "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
453 { $description "Tests if the quotation yields a true value when applied to either " { $snippet "x" } " or " { $snippet "y" } "." }
454 { $examples
455     { $example "USING: kernel math prettyprint ;" "3 6 [ odd? ] either? ." "t" }
456     { $example "USING: kernel math prettyprint ;" "5 7 [ even? ] either? ." "f" }
457 } ;
458
459 HELP: call
460 { $values { "callable" callable } }
461 { $description "Calls a quotation." }
462 { $examples
463     "The following two lines are equivalent:"
464     { $code "2 [ 2 + 3 * ] call" "2 2 + 3 *" }
465 } ;
466
467 HELP: call-clear ( quot -- )
468 { $values { "quot" callable } }
469 { $description "Calls a quotation with an empty call stack. If the quotation returns, Factor will exit.." }
470 { $notes "Used to implement " { $link "threads" } "." } ;
471
472 HELP: slip
473 { $values { "quot" quotation } { "x" object } }
474 { $description "Calls a quotation while hiding the top of the stack." } ;
475
476 HELP: 2slip
477 { $values { "quot" quotation } { "x" object } { "y" object } }
478 { $description "Calls a quotation while hiding the top two stack elements." } ;
479
480 HELP: 3slip
481 { $values { "quot" quotation } { "x" object } { "y" object } { "z" object } }
482 { $description "Calls a quotation while hiding the top three stack elements." } ;
483
484 HELP: keep
485 { $values { "quot" "a quotation with stack effect " { $snippet "( x -- )" } } { "x" object } }
486 { $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." } ;
487
488 HELP: 2keep
489 { $values { "quot" "a quotation with stack effect " { $snippet "( x y -- )" } } { "x" object } { "y" object } }
490 { $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ;
491
492 HELP: 3keep
493 { $values { "quot" "a quotation with stack effect " { $snippet "( x y z -- )" } } { "x" object } { "y" object } { "z" object } }
494 { $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ;
495
496 HELP: bi
497 { $values { "x" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x -- ... )" } } }
498 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } "." }
499 { $examples
500     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
501     { $code
502         "[ p ] [ q ] bi"
503         "dup p q"
504     }
505     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x -- y )" } ", then the following two lines are equivalent:"
506     { $code
507         "[ p ] [ q ] bi"
508         "dup p swap q"
509     }
510     "In general, the following two lines are equivalent:"
511     { $code
512         "[ p ] [ q ] bi"
513         "[ p ] keep q"
514     }
515     
516 } ;
517
518 HELP: 2bi
519 { $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y -- ... )" } } }
520 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values." }
521 { $examples
522     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
523     { $code
524         "[ p ] [ q ] 2bi"
525         "2dup p q"
526     }
527     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y -- z )" } ", then the following two lines are equivalent:"
528     { $code
529         "[ p ] [ q ] 2bi"
530         "2dup p -rot q"
531     }
532     "In general, the following two lines are equivalent:"
533     { $code
534         "[ p ] [ q ] 2bi"
535         "[ p ] 2keep q"
536     }
537 } ;
538
539 HELP: 3bi
540 { $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } }
541 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values." }
542 { $examples
543     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
544     { $code
545         "[ p ] [ q ] 3bi"
546         "3dup p q"
547     }
548     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y z -- w )" } ", then the following two lines are equivalent:"
549     { $code
550         "[ p ] [ q ] 3bi"
551         "3dup p -roll q"
552     }
553     "In general, the following two lines are equivalent:"
554     { $code
555         "[ p ] [ q ] 3bi"
556         "[ p ] 3keep q"
557     }
558 } ;
559
560 HELP: tri
561 { $values { "x" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x -- ... )" } } }
562 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } ", and finally applies " { $snippet "r" } " to " { $snippet "x" } "." }
563 { $examples
564     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
565     { $code
566         "[ p ] [ q ] [ r ] tri"
567         "dup p dup q r"
568     }
569     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x -- y )" } ", then the following two lines are equivalent:"
570     { $code
571         "[ p ] [ q ] [ r ] tri"
572         "dup p over q rot r"
573     }
574     "In general, the following two lines are equivalent:"
575     { $code
576         "[ p ] [ q ] [ r ] tri"
577         "[ p ] keep [ q ] keep r"
578     }
579 } ;
580
581 HELP: 2tri
582 { $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x y -- ... )" } } }
583 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values, and finally applies " { $snippet "r" } " to the two input values." }
584 { $examples
585     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
586     { $code
587         "[ p ] [ q ] [ r ] 2tri"
588         "2dup p 2dup q r"
589     }
590     "In general, the following two lines are equivalent:"
591     { $code
592         "[ p ] [ q ] [ r ] 2tri"
593         "[ p ] 2keep [ q ] 2keep r"
594     }
595 } ;
596
597 HELP: 3tri
598 { $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( x y z -- ... )" } } }
599 { $description "Applies " { $snippet "p" } " to the three input values, then applies " { $snippet "q" } " to the three input values, and finally applies " { $snippet "r" } " to the three input values." }
600 { $examples
601     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
602     { $code
603         "[ p ] [ q ] [ r ] 3tri"
604         "3dup p 3dup q r"
605     }
606     "In general, the following two lines are equivalent:"
607     { $code
608         "[ p ] [ q ] [ r ] 3tri"
609         "[ p ] 3keep [ q ] 3keep r"
610     }
611 } ;
612
613
614 HELP: bi*
615 { $values { "x" object } { "y" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y -- ... )" } } }
616 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } "." }
617 { $examples
618     "The following two lines are equivalent:"
619     { $code
620         "[ p ] [ q ] bi*"
621         ">r p r> q"
622     }
623 } ;
624
625 HELP: 2bi*
626 { $values { "w" object } { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( w x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y z -- ... )" } } }
627 { $description "Applies " { $snippet "p" } " to " { $snippet "w" } " and " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } " and " { $snippet "z" } "." }
628 { $examples
629     "The following two lines are equivalent:"
630     { $code
631         "[ p ] [ q ] 2bi*"
632         ">r >r q r> r> q"
633     }
634 } ;
635
636 HELP: tri*
637 { $values { "x" object } { "y" object } { "z" object } { "p" "a quotation with stack effect " { $snippet "( x -- ... )" } } { "q" "a quotation with stack effect " { $snippet "( y -- ... )" } } { "r" "a quotation with stack effect " { $snippet "( z -- ... )" } } }
638 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } ", and finally applies " { $snippet "r" } " to " { $snippet "z" } "." }
639 { $examples
640     "The following two lines are equivalent:"
641     { $code
642         "[ p ] [ q ] [ r ] tri*"
643         ">r >r p r> q r> r"
644     }
645 } ;
646
647 HELP: bi@
648 { $values { "x" object } { "y" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }
649 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } "." }
650 { $examples
651     "The following two lines are equivalent:"
652     { $code
653         "[ p ] bi@"
654         ">r p r> p"
655     }
656     "The following two lines are also equivalent:"
657     { $code
658         "[ p ] bi@"
659         "[ p ] [ p ] bi*"
660     }
661 } ;
662
663 HELP: 2bi@
664 { $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" "a quotation with stack effect " { $snippet "( obj1 obj2 -- )" } } }
665 { $description "Applies the quotation to " { $snippet "w" } " and " { $snippet "x" } ", then to " { $snippet "y" } " and " { $snippet "z" } "." }
666 { $examples
667     "The following two lines are equivalent:"
668     { $code
669         "[ p ] 2bi@"
670         ">r >r p r> r> p"
671     }
672     "The following two lines are also equivalent:"
673     { $code
674         "[ p ] 2bi@"
675         "[ p ] [ p ] 2bi*"
676     }
677 } ;
678
679 HELP: tri@
680 { $values { "x" object } { "y" object } { "z" object } { "quot" "a quotation with stack effect " { $snippet "( obj -- )" } } }
681 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } ", and finally to " { $snippet "z" } "." }
682 { $examples
683     "The following two lines are equivalent:"
684     { $code
685         "[ p ] tri@"
686         ">r >r p r> p r> p"
687     }
688     "The following two lines are also equivalent:"
689     { $code
690         "[ p ] tri@"
691         "[ p ] [ p ] [ p ] tri*"
692     }
693 } ;
694
695 HELP: if
696 { $values { "?" "a generalized boolean" } { "true" quotation } { "false" quotation } }
697 { $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation. Otherwise calls the " { $snippet "true" } " quotation."
698 $nl
699 "The " { $snippet "cond" } " value is removed from the stack before either quotation is called." } ;
700
701 HELP: when
702 { $values { "?" "a generalized boolean" } { "true" quotation } }
703 { $description "If " { $snippet "cond" } " is not " { $link f } ", calls the " { $snippet "true" } " quotation."
704 $nl
705 "The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
706
707 HELP: unless
708 { $values { "?" "a generalized boolean" } { "false" quotation } }
709 { $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation."
710 $nl
711 "The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
712
713 HELP: if*
714 { $values { "?" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" quotation } }
715 { $description "Alternative conditional form that preserves the " { $snippet "cond" } " value if it is true."
716 $nl
717 "If the condition is true, it is retained on the stack before the " { $snippet "true" } " quotation is called. Otherwise, the condition is removed from the stack and the " { $snippet "false" } " quotation is called."
718 $nl
719 "The following two lines are equivalent:"
720 { $code "X [ Y ] [ Z ] if*" "X dup [ Y ] [ drop Z ] if" } } ;
721
722 HELP: when*
723 { $values { "?" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } }
724 { $description "Variant of " { $link if* } " with no false quotation."
725 $nl
726 "The following two lines are equivalent:"
727 { $code "X [ Y ] when*" "X dup [ Y ] [ drop ] if" } } ;
728
729 HELP: unless*
730 { $values { "?" "a generalized boolean" } { "false" "a quotation " } }
731 { $description "Variant of " { $link if* } " with no true quotation." }
732 { $notes
733 "The following two lines are equivalent:"
734 { $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } } ;
735
736 HELP: ?if
737 { $values { "default" object } { "cond" "a generalized boolean" } { "true" "a quotation with stack effect " { $snippet "( cond -- )" } } { "false" "a quotation with stack effect " { $snippet "( default -- )" } } }
738 { $description "If the condition is " { $link f } ", the " { $snippet "false" } " quotation is called with the " { $snippet "default" } " value on the stack. Otherwise, the " { $snippet "true" } " quotation is called with the condition on the stack." }
739 { $notes
740 "The following two lines are equivalent:"
741 { $code "[ X ] [ Y ] ?if" "dup [ nip X ] [ drop Y ] if" }
742 "The following two lines are equivalent:"
743 { $code "[ ] [ ] ?if" "swap or" } } ;
744
745 HELP: die
746 { $description "Starts the front-end processor (FEP), which is a low-level debugger which can inspect memory addresses and the like. The FEP is also entered when a critical error occurs." }
747 { $notes
748     "The term FEP originates from the Lisp machines of old. According to the Jargon File,"
749     $nl
750     { $strong "fepped out" } " /fept owt/ " { $emphasis "adj." }  " The Symbolics 3600 LISP Machine has a Front-End Processor called a `FEP' (compare sense 2 of box). When the main processor gets wedged, the FEP takes control of the keyboard and screen. Such a machine is said to have `fepped out' or `dropped into the fep'." 
751     $nl
752     { $url "http://www.jargon.net/jargonfile/f/feppedout.html" }
753 } ;
754
755 HELP: (clone) ( obj -- newobj )
756 { $values { "obj" object } { "newobj" "a shallow copy" } }
757 { $description "Outputs a byte-by-byte copy of the given object. User code should call " { $link clone } " instead." } ;
758
759 HELP: declare
760 { $values { "spec" "an array of class words" } }
761 { $description "Declares that the elements at the top of the stack are instances of the classes in " { $snippet "spec" } "." }
762 { $warning "The compiler blindly trusts declarations, and false declarations can lead to crashes, memory corruption and other undesirable behavior." }
763 { $examples
764     "The optimizer cannot do anything with the below code:"
765     { $code "2 + 10 *" }
766     "However, if we declare that the top of the stack is a " { $link float } ", then type checks and generic dispatch are eliminated, and the compiler can use unsafe intrinsics:"
767     { $code "{ float } declare 2 + 10 *" }
768 } ;
769
770 HELP: tag ( object -- n )
771 { $values { "object" object } { "n" "a tag number" } }
772 { $description "Outputs an object's tag number, between zero and one less than " { $link num-tags } ". This is implementation detail and user code should call " { $link class } " instead." } ;
773
774 HELP: getenv ( n -- obj )
775 { $values { "n" "a non-negative integer" } { "obj" object } }
776 { $description "Reads an object from the Factor VM's environment table. User code never has to read the environment table directly; instead, use one of the callers of this word." } ;
777
778 HELP: setenv ( obj n -- )
779 { $values { "n" "a non-negative integer" } { "obj" object } }
780 { $description "Writes an object to the Factor VM's environment table. User code never has to write to the environment table directly; instead, use one of the callers of this word." } ;
781
782 HELP: object
783 { $class-description
784     "The class of all objects. If a generic word defines a method specializing on this class, the method is used as a fallback, if no other applicable method is found. For instance:"
785     { $code "GENERIC: enclose" "M: number enclose 1array ;" "M: object enclose ;" }
786 } ;
787
788 HELP: null
789 { $class-description
790     "The canonical empty class with no instances."
791 } ;
792
793 HELP: most
794 { $values { "x" object } { "y" object } { "quot" "a quotation with stack effect " { $snippet "( x y -- ? )" } } { "z" "either " { $snippet "x" } " or " { $snippet "y" } } }
795 { $description "If the quotation yields a true value when applied to " { $snippet "x" } " and " { $snippet "y" } ", outputs " { $snippet "x" } ", otherwise outputs " { $snippet "y" } "." } ;
796
797 HELP: curry
798 { $values { "obj" object } { "quot" callable } { "curry" curry } }
799 { $description "Partial application. Outputs a " { $link callable } " which first pushes " { $snippet "obj" } " and then calls " { $snippet "quot" } "." }
800 { $class-description "The class of objects created by " { $link curry } ". These objects print identically to quotations and implement the sequence protocol, however they only use two cells of storage; a reference to the object and a reference to the underlying quotation." }
801 { $notes "Even if " { $snippet "obj" } " is a word, it will be pushed as a literal."
802 $nl
803 "This operation is efficient and does not copy the quotation." }
804 { $examples
805     { $example "USING: kernel prettyprint ;" "5 [ . ] curry ." "[ 5 . ]" }
806     { $example "USING: kernel prettyprint ;" "\\ = [ see ] curry ." "[ \\ = see ]" }
807     { $example "USING: kernel math prettyprint sequences ;" "{ 1 2 3 } 2 [ - ] curry map ." "{ -1 0 1 }" }
808 } ;
809
810 HELP: 2curry
811 { $values { "obj1" object } { "obj2" object } { "quot" callable } { "curry" curry } }
812 { $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } " and " { $snippet "obj2" } " and then calls " { $snippet "quot" } "." }
813 { $notes "This operation is efficient and does not copy the quotation." }
814 { $examples
815     { $example "USING: kernel math prettyprint ;" "5 4 [ + ] 2curry ." "[ 5 4 + ]" }
816 } ;
817
818 HELP: 3curry
819 { $values { "obj1" object } { "obj2" object } { "obj3" object } { "quot" callable } { "curry" curry } }
820 { $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } ", " { $snippet "obj2" } " and " { $snippet "obj3" } ", and then calls " { $snippet "quot" } "." }
821 { $notes "This operation is efficient and does not copy the quotation." } ;
822
823 HELP: with
824 { $values { "param" object } { "obj" object } { "quot" "a quotation with stack effect " { $snippet "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
825 { $description "Partial application on the left. The following two lines are equivalent:"
826     { $code "swap [ swap A ] curry B" }
827     { $code "[ A ] with B" }
828     
829 }
830 { $notes "This operation is efficient and does not copy the quotation." }
831 { $examples
832     { $example "USING: kernel math prettyprint sequences ;" "2 { 1 2 3 } [ - ] with map ." "{ 1 0 -1 }" }
833 } ;
834
835 HELP: compose
836 { $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
837 { $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
838 { $notes
839     "The two quotations must leave the retain stack in the same state on exit as it was on entry, so the following code is not allowed:"
840     { $code
841         "[ 3 >r ] [ r> . ] compose"
842     }
843     "Except for this restriction, the following two lines are equivalent:"
844     { $code
845         "compose call"
846         "append call"
847     }
848     "However, " { $link compose } " runs in constant time, and the optimizing compiler is able to compile code which calls composed quotations."
849 } ;
850
851
852 HELP: prepose
853 { $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
854 { $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot2" } " followed by " { $snippet "quot1" } "." }
855 { $notes "See " { $link compose } " for details." } ;
856
857 { compose prepose } related-words
858
859 HELP: 3compose
860 { $values { "quot1" callable } { "quot2" callable } { "quot3" callable } { "compose" compose } }
861 { $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } ", " { $snippet "quot2" } " and then " { $snippet "quot3" } "." }
862 { $notes
863     "The three quotations must leave the retain stack in the same state on exit as it was on entry, so for example, the following code is not allowed:"
864     { $code
865         "[ >r ] swap [ r> ] 3compose"
866     }
867     "The correct way to achieve the effect of the above is the following:"
868     { $code
869         "[ dip ] curry"
870     }
871     "Excepting the retain stack restriction, the following two lines are equivalent:"
872     { $code
873         "3compose call"
874         "3append call"
875     }
876     "However, " { $link 3compose } " runs in constant time, and the compiler is able to compile code which calls composed quotations."
877 } ;
878
879 HELP: dip
880 { $values { "obj" object } { "quot" quotation } }
881 { $description "Calls " { $snippet "quot" } " with " { $snippet "obj" } " hidden on the retain stack." }
882 { $notes "The following are equivalent:"
883     { $code ">r foo bar r>" }
884     { $code "[ foo bar ] dip" }
885 } ;
886
887 HELP: 2dip
888 { $values { "obj1" object } { "obj2" object } { "quot" quotation } }
889 { $description "Calls " { $snippet "quot" } " with " { $snippet "obj1" } " and " { $snippet "obj2" } " hidden on the retain stack." }
890 { $notes "The following are equivalent:"
891     { $code ">r >r foo bar r> r>" }
892     { $code "[ foo bar ] 2dip" }
893 } ;
894
895 HELP: while
896 { $values { "pred" "a quotation with stack effect " { $snippet "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
897 { $description "Repeatedly calls " { $snippet "pred" } ". If it yields " { $link f } ", iteration stops, otherwise " { $snippet "body" } " is called. After iteration stops, " { $snippet "tail" } " is called." }
898 { $notes "In most cases, tail recursion should be used, because it is simpler both in terms of implementation and conceptually. However in some cases this combinator expresses intent better and should be used."
899 $nl
900 "Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
901 { $code
902     "[ P ] [ Q ] [ T ] while"
903     "[ P ] [ Q ] [ ] while T"
904 }
905 "However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference." } ;
906
907 HELP: assert
908 { $values { "got" "the obtained value" } { "expect" "the expected value" } }
909 { $description "Throws an " { $link assert } " error." }
910 { $error-description "Thrown when a unit test or other assertion fails." } ;