factor/doc/handbook/objects.facts

190 lines
10 KiB
Plaintext

USING: generic help kernel lists sequences ;
GLOSSARY: "object" "a datum which may appear on the stack" ;
ARTICLE: "objects" "Objects"
"Objects model data in Factor. Objects have unique identity, and either hold intrinsic value -- for example, an integer object -- or are composed from named slots, each slot holding an object."
{ $subsection "equality" }
{ $subsection "generic" }
{ $subsection "classes" }
{ $subsection "tuples" } ;
GLOSSARY: "equal" "two objects are equal if they have the same class and if their slots are equal, or alternatively, if both are numbers denoting the same value" ;
ARTICLE: "equality" "Equality and comparison testing"
"There are two distinct notions of ``sameness'' when it comes to objects. You can test if two references point to the same object, or you can test if two objects are equal in some sense, usually by being instances of the same class, and having equal slot values. Both notions of equality are equality relations in the mathematical sense."
{ $subsection eq? }
{ $subsection = }
"Some types of objects also have an intrinsic order allowing sorting using " { $link natural-sort } ":"
{ $subsection <=> }
"An object can be cloned; the clone has distinct identity but equal value:"
{ $subsection clone } ;
GLOSSARY: "generic word" "a word defined via the " { $link POSTPONE: GENERIC: } " or " { $link POSTPONE: G: } " parsing word. A generic word is comprised of a set of methods and a method combination. Methods are keyed by classes, and the method combination determines which stack element is inspected and which methods are called when the generic word executes." ;
GLOSSARY: "method"
"gives the behavior of a generic word when dispatching on a specific class" ;
ARTICLE: "generic" "Generic words and methods"
"A generic word's behavior depends on the class of the object at the top of the stack, although this can be generalized using custom method combination. A specific behavior of a generic word on a class is called a " { $emphasis "method" } "."
$terpri
"The key advantage of a generic word over a set of conditional tests is that methods are defined in a decentralized manner, thus adding new methods does not force unnecessary coupling between code."
$terpri
"In the overwhelming majority of cases, your interaction with the generic word system centers on two parsing words:"
{ $subsection POSTPONE: GENERIC: }
{ $subsection POSTPONE: M: }
"Since classes are not linearly ordered, method ordering is an issue to keep in mind."
{ $subsection "method-order" }
{ $subsection "method-combination" } ;
ARTICLE: "method-order" "Method ordering"
"If two classes have a non-empty intersection, there is no guarantee that one is a subclass of the other. This means there is no canonical linear ordering of classes."
$terpri
"Consider the following set of definitions:"
{ $code
"GENERIC: explain"
"M: general-t explain drop \"a true value\" print ;"
"M: general-list explain drop \"a list\" print ;"
"M: object explain drop \"an object\" print ;"
}
"Neither " { $link general-t } " nor " { $link general-list } " contains the other, yet their intersection is the non-empty " { $link cons } " class. So the generic word system will place " { $link object } " first in the method order, however either " { $link general-t } " or " { $link general-list } " may come next, and it is pretty much a random choice that depends on hashing:"
{ $example "\\ bar order ." "{ object general-list general-t }" }
"Therefore, the outcome of calling " { $snippet "bar" } " with a cons cell as input is undefined."
$terpri
"As you can see above, the " { $link order } " word can be useful to clarify method dispatch."
{ $subsection order } ;
GLOSSARY: "method combination" "control flow glue between methods in a generic word" ;
ARTICLE: "method-combination" "Method combination"
"Abstractly, a generic word can be thought of as a big chain of type conditional tests applied to the top of the stack, with methods as the bodies of each test. The " { $emphasis "method combination" } " is this control flow glue between the set of methods, and several aspects of it can be customized:"
{ $list
"which stack item(s) the generic word dispatches upon,"
"which methods out of the set of applicable methods are called"
}
"The " { $link POSTPONE: GENERIC: } " parsing word creates a generic word using the " { $emphasis "simple method combination" } ". Most generic words that come up in practice use this method combination:"
{ $subsection simple-combination }
"The " { $link POSTPONE: G: } " parsing word allows a different method combination to be specified:"
{ $subsection POSTPONE: G: }
"The simple method combination is a special case of the standard method combination:"
{ $subsection standard-combination }
"Another combination for arithmetic operators:"
{ $subsection math-combination }
"If nothing else will do:"
{ $subsection "custom-combination" } ;
ARTICLE: "custom-combination" "Custom method combination"
"Developing a custom method combination requires a good understanding of higher-order programming (code that writes code) and Factor internals. Custom method combination has not been fully explored at this stage of Factor development, and this section can only give a brief sketch of what is involved."
$terpri
"A method combination quotation has stack effect " { $snippet "( word -- quot )" } "."
$terpri
"Generic words can be introspected:"
{ $subsection methods }
"Code generation utilities:"
{ $subsection alist>quot }
{ $subsection curry }
"Generic word generation utilities:"
{ $subsection class-predicates }
{ $subsection simplify-alist }
{ $subsection math-upgrade }
{ $subsection object-method } ;
GLOSSARY: "class" "a set of objects on which generic words can specialize methods" ;
ARTICLE: "classes" "Classes"
"A class is a set of objects on which generic words can specialize methods. Each class has a membership predicate named after the class with a \"?\" suffix, with the following two exceptions:"
{ $list
{ { $link object } " - there is no need for a predicate word, since every object is an instance of this class" }
{ { $link general-t } " - there is no need for a predicate word, since the " { $link if } " combinator makes an implicit test for instances of this class" }
}
{ $subsection object }
{ $subsection "builtin-classes" }
{ $subsection "unions" }
{ $subsection "predicates" }
{ $subsection "class-operations" } ;
GLOSSARY: "type" "an object invariant that describes its shape. An object's type is constant for the lifetime of the object, and there is only a fixed number of types built-in to the run-time. See class" ;
GLOSSARY: "built-in class" "see type" ;
ARTICLE: "builtin-classes" "Built-in classes"
"Every object is an instance of to exactly one type, and the type is constant for the lifetime of the object. There is only a fixed number of types built-in to the run-time, and corresponding to each type is a " { $emphasis "built-in class" } ":"
{ $code
"alien"
"array"
"bignum"
"byte-array"
"complex"
"cons"
"displaced-alien"
"dll"
"f"
"fixnum"
"float"
"ratio"
"sbuf"
"string"
"t"
"tuple"
"vector"
"word"
"wrapper"
}
{ $subsection type }
{ $subsection class } ;
GLOSSARY: "union" "a class whose set of instances is the union of the set of instances of a list of member classes" ;
ARTICLE: "unions" "Union classes"
"An object is an instance of a union class if it is an instance of one of its members. Union classes are used to associate the same method with several different classes, as well as to conveniently define predicates."
{ $subsection POSTPONE: UNION: }
{ $subsection define-union }
{ $subsection union } ;
GLOSSARY: "predicate" "a word with stack effect " { $snippet "( object -- ? )" } ", or alternatively, a class whose instances are the instances of a superclass that satisfy an arbitrary predicate" ;
ARTICLE: "predicates" "Predicate classes"
"Predicate classes allow fine-grained control over method dispatch."
{ $subsection POSTPONE: PREDICATE: }
{ $subsection define-predicate-class }
{ $subsection predicate } ;
ARTICLE: "class-operations" "Class operations"
{ $subsection class< }
{ $subsection class-compare }
{ $subsection class-and }
{ $subsection types } ;
ARTICLE: "tuples" "Tuples"
"Tuples are user-defined classes composed of named slots. All tuples have the same type, however distinct classes of tuples are defined."
$terpri
"A parsing word defines tuple classes."
{ $subsection POSTPONE: TUPLE: }
{ $subsection "tuple-constructors" }
{ $subsection "tuple-delegation" } ;
GLOSSARY: "constructor" "a word whose primary role is to create new instances of a class" ;
ARTICLE: "tuple-constructors" "Constructors and slots"
"New instances of tuple classes are created by calling a constructor word, whose name is the tuple's name surrounded by angle brackets:"
{ $code "TUPLE: point x y z ;\n1 2 3 <point>" }
"The default constructor stores stack elements into consecutive slots, with the top of the stack going into the rightmost slot."
$terpri
"After construction, slots are read and written using various automatically-defined words with names of the form " { $snippet { $emphasis "class-slot" } } " and " { $snippet "set-" { $emphasis "class-slot" } } "."
$terpri
"Custom constructors can be defined:"
{ $subsection POSTPONE: C: } ;
GLOSSARY: "delegate" "an object acting as a sink for unhandled method calls on behalf of another object" ;
ARTICLE: "tuple-delegation" "Delegation"
"Each tuple can have an optional delegate tuple. Most generic words called on the tuple that do not have a method for the tuple's class will be passed on to the delegate."
$terpri
"More precisely, any generic word using " { $link simple-combination } " delegates, and this includes all generic words defined via the " { $link POSTPONE: GENERIC: } " parsing word."
$terpri
"Factor uses delegation in place of implementation inheritance, but it is not a direct substitute; in particular, the semantics differ in that a delegated method call receives the delegate on the stack, not the original object."
{ $warning "Delegation to objects that are not tuples is not fully supported. Generic words support delegation to arbitrary types, as do slot accessors which are built from generic words. However, type-specific primitives do not." }
{ $subsection delegate }
{ $subsection set-delegate }
"There is a combinator to recursively apply a predicate to a delegate chain:"
{ $subsection is? } ;