diff --git a/doc/devel-guide.tex b/doc/devel-guide.tex index 3fc2bcaad8..c5ae07901d 100644 --- a/doc/devel-guide.tex +++ b/doc/devel-guide.tex @@ -334,12 +334,7 @@ matters (\texttt{-} and \texttt{/}), the operands are taken in the natural order \textbf{111} \end{alltt} -The \texttt{neg} unary operator negates the number at the top of the stack (that is, multiplies it by -1). Two unary operators \texttt{pred} and \texttt{succ} subtract 1 and add 1, respectively, to the number at the top of the stack. - -\begin{alltt} -\textbf{ok} 5 pred pred succ neg . -\textbf{-4} -\end{alltt} +The \texttt{neg} word negates the number at the top of the stack (that is, multiplies it by -1). This type of arithmetic is called \emph{postfix}, because the operator follows the operands. Contrast this with \emph{infix} notation used diff --git a/doc/generic.txt b/doc/generic.txt new file mode 100644 index 0000000000..224deb1cad --- /dev/null +++ b/doc/generic.txt @@ -0,0 +1,272 @@ +THE FACTOR GENERIC WORD SYSTEM + +Factor's generic word system is a very abstract generalization of +"object oriented" features found in other programming languges. + +To use the generic word system, you must put the following near the +beginning of your source file: + +USE: generic + +The key motivation is that sometimes, you want to write a word that has +differing behavior depending on the class of its argument. For example, +in a game, a 'draw' word could take different action if given a ship, a +weapon, a planet, etc. + +Duplicating 'type case' logic is undesirable and also results in +unnecessary coupling -- adding support for a new type of graphical +object would require modifying the original definition of 'draw', for +example. + +* Types + +In Factor, the idea of a 'type' refers to a very concrete concept. The +type of an object is its representation in runtime object memory. Types +include fixnums, bignums, cons cells, vectors, strings, and so on. The +set of available types is fixed; adding a new type requires modifying +the runtime source written in C. + +* Classes + +In Factor, a 'class' is just a predicate that categorizes objects as +being a member of the class or not. To be useful, it must be consistent +-- for a given object, it must always return the same truth value. + +Examples of classes might include: + +- Cons cells where both elements are integers + +- Floating point numbers between -1 and 1 + +- Hash tables holding a certain key + +- Any object that occurs as a member of a certain global variable +holding a list. + +- ... and so on. + +As you can see, a class of objects does not need to be a subset or a +superset of a type of objects. + +Classes, unlike types, can be defined by the user. + +* Generic words + +A generic word is a word whose behavior depends on the class of the +object at the top of the stack. + +Generic words are defined using the following syntax: + +GENERIC: draw ( actor -- ) +#! Draw the actor. + +A stack effect comment, as above, is not required but recommended. + +* Methods + +A method associates behavior to a generic word. Methods are defined by +writing M:, followed by a class name, followed by the name of a +previously-defined generic word. + +One of the main benefits of generic words is that each method definition +can potentially occur in a different source file. Generic word +definitions also hide conditionals. + +Here are two methods for the generic 'draw' word: + +M: ship draw ( actor -- ) + [ + surface get screen-xy radius get color get + filledCircleColor + ] bind ; + +M: plasma draw ( actor -- ) + [ + surface get screen-xy dup len get + color get + vlineColor + ] bind ; + +Here, 'ship' and 'class' are user-defined classes. + +* Metaclasses + +To understand what classes already exist, and how to define your own +classes, the concept of a 'metaclass' must be grasped first. Roughly +speaking, a metaclass is a class of classes. + +New metaclasses can be defined by the user, but its an involved process +that requires a deeper understanding of the generic word systsem than +can be given here. + +** The object class + +Every object is a member of the object class. The object class is also a +metaclass, and it is the one and only instance of itself. + +Confusing? The idea is pretty simple. If you define a method on +'object', it will be called when no more specific method is available: + +GENERIC: describe +M: number describe "The number " write . ; +M: object describe "I don't know anything about " write . ; + +Since the only instance of the object metaclass is itself, you cannot +define new classes in the object metaclass. + +** The builtin metaclass + +The builtin metaclass contains precisely the following classes; each +class corresponds to a runtime type: + +alien +array +bignum +complex +cons +dll +f +fixnum +float +port +ratio +sbuf +string +t +vector +word + +Each builtin class has a corresponding membership test predicate, named +after the builtin class suffixed with '?'. For example, cons?, word?, +etc. + +Adding new classes to the builtin metaclass requires modifications to +the C code comprising Factor's runtime. + +** The union metaclass + +The union metaclass contains classes whose members are defined to be the +aggregate of the members of a list of existing classes. + +For example, the Factor library defines some unions over numeric types: + +UNION: integer fixnum bignum ; +UNION: rational integer ratio ; +UNION: real rational float ; +UNION: number real complex ; + +Now, the absolute value function can be defined in an efficient manner +for real numbers, and in a more general fashion for complex numbers: + +GENERIC: abs ( z -- |z| ) +M: real abs dup 0 < [ neg ] when ; +M: complex abs >rect mag2 ; + +New unions can be defined by you, and the numerical types example above +gives the syntax: you write UNION: followed by the name of the union, +followed by its members. The list of members is terminated with a +semi-colon. + +A predicate named after the union followed by '?' is +automatically-defined. For example, the following definition of 'real?' +was automatically created: + +: real? + dup rational? [ + drop t + ] [ + dup float? [ + drop t + ] [ + drop f + ] ifte + ] ifte ; + +** The predicate metaclass + +The predicate metaclass contains classes whose membership test is an +arbitrary expression. To speed up dispatch, each predicate must be +defined as a subclass of some other class. That way predicates +subclassing from disjoint builtin classes do not need to be +simultaenously tested. + +The library/strings.factor module defines some subclasses of integer, +classifying the different types of ASCII characters: + +PREDICATE: integer blank " \t\n\r" str-contains? ; +PREDICATE: integer letter CHAR: a CHAR: z between? ; +PREDICATE: integer LETTER CHAR: A CHAR: Z between? ; +PREDICATE: integer digit CHAR: 0 CHAR: 9 between? ; +PREDICATE: integer printable CHAR: \s CHAR: ~ between? ; + +Each predicate defines a corresponding predicate word whose name is +suffixed with '?'; for example, a 'digit?' word is automatically +defined: + +: digit? + dup integer? [ + CHAR: 0 CHAR: 9 between? + ] [ + drop f + ] ifte ; + +For obvious reasons, the predicate definition must consume and produce +exactly one value on the stack. + +** The traits metaclass + +(The name for this metaclass is wrong and will change eventually. The +original idea was to allow an object to inherit any number of 'traits', +thus they would behave like mixins. This never materialized.) + +The traits metaclass allows one to associate more fine-grained behavior, +specifically with hashtables. + +New classes can be defined like so: + +TRAITS: plasma + +In terms of behavior, this is actually identical to the following: + +PREDICATE: hashtable plasma \ traits swap hash plasma = ; + +However, it is far more efficient (and less verbose). + +You can define methods as usual: + +GENERIC: collide ( actor1 actor2 -- ) + +M: plasma collide ( actor1 actor2 -- ) + #! Remove the other actor. + deactivate deactivate ; + +How does one actually get an object that plasma? responds with t to? You +define a constructor word by writing C: followed by the class name: + +C: plasma ( actor dy -- plasma ) + [ + velocity set + actor-xy + blue color set + 10 len set + 5 radius set + active on + ] extend ; + +The constructor word is named after the class, surrounded in angle +brackets (< and >). For example, the above actually creates a word named +. + +The constructor's definition begins with the parameters given by the +user, underneath a blank plasma object. + +That is, a dummy constructor just returns a blank hashtable that +responds t to the corresponding membership predicate: + +TRAITS: foo +C: foo ; + + foo? . +==> t + +"hello" foo? . +==> f diff --git a/factor/ExternalFactor.java b/factor/ExternalFactor.java index 69708e5f63..ec969e9f64 100644 --- a/factor/ExternalFactor.java +++ b/factor/ExternalFactor.java @@ -89,7 +89,7 @@ public class ExternalFactor extends DefaultVocabularyLookup out.write("USE: jedit wire-server\n".getBytes("ASCII")); out.flush(); waitForAck(); - } + } //}}} //{{{ waitForAck() method private void waitForAck() throws IOException @@ -104,6 +104,7 @@ public class ExternalFactor extends DefaultVocabularyLookup byte[] discard = new byte[2048]; int len = in.read(discard,0,discard.length); discardStr = new String(discard,0,len); + Log.log(Log.DEBUG,this,"Waiting for ACK: " + discardStr); } } //}}}