What are OOP's Jargons and Complexities?

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Xah Lee

    What are OOP's Jargons and Complexities?


    What are OOP's Jargons and Complexities
    Xah Lee, 20050128

    The Rise of Classes, Methods, Objects

    In computer languages, often a function definition looks like this:
    subroutine f (x1, x2, ...) {
    variables ...
    do this or that
    }

    In advanced languages such as LISP family, it is not uncommon to define
    functions inside a function. For example:
    subroutine f (x1, x2, ...) {
    variables...
    subroutine f1 (x1...) {...}
    subroutine f2 (x1...) {...}
    }

    Often these f1 f2 inner functions are used inside f, and are not
    relevant outside of f. Such power of the language gradually developed
    into a style of programing. For example:
    subroutine a_surface () {
    coordinatesList = ...;
    subroutine translate (distance) {...}
    subroutine rotate (angle) {..}
    }

    Such a style is that the a_surface is no longer viewed as a function.
    But instead, a boxed set of functions, centered around a piece of data.
    And, all functions for manipulating this piece of data are all embodied
    in this function. For example:
    subroutine a_surface (arg) {
    coordinatesList = ...
    subroutine translate (distance) {set coordinatesList to translated
    version}
    subroutine rotate (angle) {set coordinatesList to rotated version}
    subroutine return () {return coordinatesList }

    if (no arg) {return coordinatesList }
    else { apply arg to coordinatesList }
    }

    In this way, one uses a_surface as a data, which comes with its owe set
    of functions:
    mySurface = a_surface();
    mySurface(rotat e(angle)); // now the surface data has been
    rotated
    mySurface(trans late(distance)) ; // now its translated
    newSurface = mySurface(retur n())

    So now, a_surface is no longer viewed as a subroutine, but a boxed set
    of things centered around a piece of data. All functions that work on
    the data are included in the boxed set. This paradigm possible in
    functional languages has refined so much so that it spread to other
    groups and became known as Object Oriented Programing, and complete
    languages with new syntax catered to such scheme emerged.

    In such languages, instead of writing them like this:
    mySurface = a_surface();
    mySurface(rotat e(angle));

    the syntax is changed to like this, for example:
    mySurface = new a_surface();
    mySurfaceRotate d = mySurface.rotat e(angle);

    In such languages, the super subroutine a_surface is no longer called a
    function or subroutine. It is now called a “Class”. And nowthe
    variable holding the function "mySurface = a_surface()" is now called a
    “Object”. Subroutines inside the function a_surface() are no longer
    called inner-subroutines. They are called “Methods”. The act of
    assigning a super-subroutine to a variable is called instantiation.

    This style of programing and language have become so fanatical that in
    such dedicated languages like Java, everything in the language are
    “Classes”. One can no longer just define a variable or subroutine.
    Instead, one creates these meta-subroutine “Classes”. Everything
    one do are inside Classes. And one assign Classes inside these Classes
    to create “Objects”. And one uses “Methods”to manipulate
    Objects. In this fashion, even basic primitives like numbers, strings,
    and lists are no longer atomic entities. They are now Classes.

    For example, in Java, a string is a class String. And inside the class
    String, there are Methods to manipulate strings, such as finding the
    number of chars, or extracting parts of the string. This can get very
    complicated. For example, in Java, there are actually two Classes of
    strings: One is String, and the other is StringBuffer. Which one to use
    depends on whether you intend to change the data.

    So, a simple code like this in normal languages:
    a = "a string";
    b = "another one";
    c = join(a,b);
    print c;

    or in lisp style
    (set a "a string")
    (set b "another one")
    (set c (join a b))
    (print c)

    becomes in pure OOP languages:
    public class test {
    public static void main(String[] args) {
    String a = new String("a string");
    String b = new String("another one");
    StringBuffer c = new StringBuffer(40 );
    c.append(a); c.append(b);
    System.out.prin tln(c.toString( ));
    }
    }

    Here, the "new String" creates a String object. The "new
    StringBuffer(40 )" creates the changeable string object StringBuffer,
    with room for 40 chars. "append" is a method of StringBuffer. It is
    used to join two Strings.

    Notice the syntax "c.append(a )", which we can view it as calling a
    inner subroutine "append", on a super subroutine that has been assigned
    to c, where, the inner subroutine modifies the inner data by appending
    a to it.

    And in the above Java example, StringBuffer class has another method
    "toString() " used to convert this into a String Class, necessary
    because System.out.prin tln's parameter requires a String type, not
    StringBuffer.

    For a example of the complexity of classes and methods, see the Java
    documentation for the StringBuffer class at

    (local copy)

    In the same way, numbers in Java have become a formalization of many
    classes: Double, Float, Integer, Long... and each has a bunch of
    "methods" to operate or convert from one to the other.

    Instead of
    aNumber = 3;
    print aNumber^3;

    In Java the programer needs to master the ins and outs of the several
    number classes, and decide which one to use. (and if a program later
    needs to change from one type of number to another, it is often
    cumbersome.)

    This Object Oriented Programing style and dedicated languages (such as
    C++, Java) have become a fad like wild fire among the programing mass
    of ignoramuses in the industry. Partly because of the data-centric new
    perspective, partly because the novelty and mysticism of new syntax and
    jargonization.

    It is especially hyped by the opportunist Sun Microsystems with the
    inception of Java, internet, and web applications booms around 1995. At
    those times, OOP (and Java) were thought to revolutionize the industry
    and solve all software engineering problems, in particular by certain
    "reuse of components" concept that was thought to come with OOP.

    As part of this new syntax and purity, where everything in a program is
    of Classes and Objects and Methods, many complex issues and concept
    have arisen in OOP.

    We now know that the jargon Class is originally and effectively just a
    boxed set of data and subroutines, all defined inside a subroutine. And
    the jargon "Object" is just a variable that has been set to this super
    subroutine. And the inner subroutines are what's called Methods.

    ----------
    to be continued tomorrow.

    This is part of an installment of the article
    “What are OOP's Jargons and Complexities”
    by Xah Lee, 20050128. The full text is at


    © Copyright 2005 by Xah Lee. Verbatim duplication of the complete
    article for non-profit purposes is granted.

    The article is published in the following newsgroups:
    comp.lang.c,com p.lang.c++,comp .lang.lisp,comp .unix.programme r
    comp.lang.pytho n,comp.lang.per l.misc,comp.lan g.scheme,comp.l ang.java.progra mmer
    comp.lang.funct ional,comp.obje ct,comp.softwar e-eng,comp.softwa re.patterns

    Xah
    xah@xahlee.org
    ∑ http://xahlee.org/

  • Eric Lavigne

    #2
    Re: What are OOP's Jargons and Complexities?

    >or in lisp style[color=blue]
    >(set a "a string")
    >(set b "another one")
    >(set c (join a b))
    >(print c)[/color]

    This code has a syntax error. If you use "set" then you have to quote
    the first argument:
    (set 'a "a string")
    Alternatively, you could use the more popular setq or setf:
    (setq a "a string")
    (setf a "a string")
    Setq is a macro whose only purpose is to transform (setq x y) to (set
    'x y) while setf is a far more powerful macro that can sometimes
    perform function inversion to accomplish its task.

    Comment

    • Eric Lavigne

      #3
      Re: What are OOP's Jargons and Complexities?

      >So, a simple code like this in normal languages:[color=blue]
      >a = "a string";
      >b = "another one";
      >c = join(a,b);
      >print c;[/color]
      [color=blue]
      >becomes in pure OOP languages:
      >public class test {
      > public static void main(String[] args) {
      > String a = new String("a string");
      > String b = new String("another one");
      > StringBuffer c = new StringBuffer(40 );
      > c.append(a); c.append(b);
      > System.out.prin tln(c.toString( ));
      > }
      >}[/color]

      I don't think it has to be that complicated. I'm new to Java, and don't
      have a compiler handy, but wouldn't this work?

      String a = new String("a string");
      String b = new String("another one");
      String c = a + b;
      System.out.prin tIn(c);

      Comment

      • Duck Dodgers

        #4
        Re: What are OOP's Jargons and Complexities?

        > a simple code like this in normal languages
        How do you define a "normal" language? Your view seems rather narrow.
        [color=blue]
        > or in lisp style[/color]
        LISP isn't a normal language? So is it an "abnormal" language, since it
        doesn't fall into your "normal" and "OOP" world of computer
        programming? If find your arguments so far to be nonsensical since
        you're having trouble with simple classification.
        [color=blue]
        > becomes in pure OOP languages[/color]
        Funny how you use the most concise syntax possible for your favored
        languages and the least concise possible for your OOP example. A better
        Java example would be:

        public class test {
        public static void main(String [] args) {
        String a = "a string";
        String b = "another one";
        String c = a + b;
        System.out.prin tln(c);
        }
        }

        Oddly enough, that's only two logical lines longer than your supposedly
        superior examples. Of course, you also need to consider that many
        programming languages (that happen to not be OOP) require some form of
        framework such as library inclusion of a function at the top lexical
        level to act as an entry point, so most runnable examples will be
        longer and more complicated whether they be OOP or not. Your example
        translated to C would look like this:

        #include <stdio.h>
        #include <string.h>

        int main(void)
        {
        char *a = "a string";
        char *b = "another one";
        char c[20];
        strcpy(c, a);
        strcat(c, b);
        puts(c);
        return 0;
        }

        C isn't OOP, yet the code is longer than even your verbose Java example
        and not any easier to understand to a newcomer. Though C isn't a high
        level scripting language, so it may be "abnormal" according to your
        definition of programming languages.
        [color=blue]
        > This Object Oriented Programing style and dedicated languages (such[/color]
        as C++, Java)
        You realize that C++ isn't an object-oriented programming language,
        right? It's a multi-paradigm language that supports several programming
        styles, among which, one is OOP. In fact, to make the best use of C++,
        you would find yourself mixing multiple styles together to get the
        powerful flexibility that makes good applications.
        [color=blue]
        > among the programing mass of ignoramuses in the industry[/color]
        You don't seem like such a bright bulb yourself. Perhaps if you gave a
        more objective and well thought out comparison of OOPL and non-OOPL
        then I (and probably most everyone else) wouldn't shrug you off as just
        another biased fool who has his head too far up his own ass to smell
        the bullshit.

        By the way, I'm not a fan of OOP, so my opinion is based completely on
        how you presented the material, not my own opinion of the topic.

        Comment

        • Jirka Klaue

          #5
          Re: What are OOP's Jargons and Complexities?

          Duck Dodgers wrote:
          [color=blue]
          > Your example translated to C would look like this:
          > #include <stdio.h>
          > #include <string.h>
          > int main(void)
          > {
          > char *a = "a string";
          > char *b = "another one";
          > char c[20];
          > strcpy(c, a);
          > strcat(c, b);
          > puts(c);
          > return 0;
          > }[/color]

          ITYM:

          #include <stdio.h>
          #include <string.h>

          int main(void)
          {
          char *a = "a string", *b = "another one", c[20];
          puts(strcat(str cpy(c, a), b));
          }

          /* ;-) */

          Jirka

          Comment

          • Ola Bini

            #6
            Re: What are OOP's Jargons and Complexities?


            If you're going to critize programming paradigms - and specific
            languages - wouldn't it be GREAT to actually be fluent in the languages
            you're talking about? There are quite a few problems with the things
            you've said:
            [color=blue]
            > We now know that the jargon Class is originally and effectively just a
            > boxed set of data and subroutines, all defined inside a subroutine. And
            > the jargon "Object" is just a variable that has been set to this super
            > subroutine. And the inner subroutines are what's called Methods.
            >[/color]

            No, this is incorrect. There is no possibility to actually model
            subclasses if a Class only was a "supersubroutin e".
            [color=blue]
            > In Java the programer needs to master the ins and outs of the several
            > number classes, and decide which one to use. (and if a program later
            > needs to change from one type of number to another, it is often
            > cumbersome.)[/color]

            This is simply NOT TRUE. Java has primitive number types, which makes
            these simple to work with, very much like C data types.
            [color=blue]
            > And in the above Java example, StringBuffer class has another method
            > "toString() " used to convert this into a String Class, necessary
            > because System.out.prin tln's parameter requires a String type, not
            > StringBuffer.[/color]

            This is, as almost all your statements, not true. What you don't mention
            is that PrintStream.pri ntln() actually is overloaded to take an Object,
            and call that objects toString() automatically.
            [color=blue]
            > For a example of the complexity of classes and methods, see the Java
            > documentation for the StringBuffer class at
            > http://java.sun.com/j2se/1.4.2/docs/...ingBuffer.html[/color]

            This doesn't actually SAY anything. I could give you a few links to CLHS
            pages, which define the functions and macros for working with strings
            and sequences, and you would easily find as much complexity there.
            [color=blue]
            > public class test {
            > public static void main(String[] args) {
            > String a = new String("a string");
            > String b = new String("another one");
            > StringBuffer c = new StringBuffer(40 );
            > c.append(a); c.append(b);
            > System.out.prin tln(c.toString( ));
            > }
            > }[/color]

            As already been noted here, the idiomatic Java way of writing this looks
            somewhat like this:

            public class Test {
            public static void main(final String[] args) {
            final String a = "a string";
            final String b = "another one";
            final String c = a + b;
            System.out.prin tln(c);
            }
            }

            Furthermore, you could do this in a simple functional style like this:
            public class Test {
            public static void main(final String[] args) {
            System.out.prin tln("a string" + "another one");
            }
            }
            [color=blue]
            > For example, in Java, a string is a class String. And inside the class
            > String, there are Methods to manipulate strings, such as finding the
            > number of chars, or extracting parts of the string. This can get very
            > complicated. For example, in Java, there are actually two Classes of
            > strings: One is String, and the other is StringBuffer. Which one to use
            > depends on whether you intend to change the data.[/color]

            This is also incorrect. The String class is the only one class available
            for handling strings. The StringBuffer/StringBuilder is simply an
            utility class.



            I do not say that OO is good for everything. In fact I hold the opposite
            view, that it's harmful in many instances. The Lisp way is almost always
            better. This critique is purely based on the fact that your column was
            very full of errors and omitted information.

            /O

            Comment

            • Duck Dodgers

              #7
              Re: What are OOP's Jargons and Complexities?

              I say what I mean and mean nothing at all. ;-) Putting aside the
              stylistic reasons for not performing multiple definitions/operations on
              a single line, my example was a direct translation of the Python-esque
              code, it wasn't intended to be the most concise C possible. And I also
              don't compile as C99, so your code would have undefined behavior for
              me. So no, that's not what I meant at all. ;-)

              Comment

              • Morten Alver

                #8
                Re: What are OOP's Jargons and Complexities?

                > ITYM:[color=blue]
                >
                > #include <stdio.h>
                > #include <string.h>
                >
                > int main(void)
                > {
                > char *a = "a string", *b = "another one", c[20];
                > puts(strcat(str cpy(c, a), b));
                > }
                >
                > /* ;-) */[/color]

                Just for the record, in Java you could write:

                String a = "a string", b = "another one", c = a+b;
                System.out.prin tln(c);

                All of this is irrelevant, the point is that the comparison by the OP is
                meaningless as an example of what OOP leads to.


                --
                Morten

                Comment

                • Stephane Zuckerman

                  #9
                  Re: What are OOP's Jargons and Complexities?

                  > ITYM:[color=blue]
                  >
                  > #include <stdio.h>
                  > #include <string.h>
                  >
                  > int main(void)
                  > {
                  > char *a = "a string", *b = "another one", c[20];
                  > puts(strcat(str cpy(c, a), b));
                  > }
                  >
                  > /* ;-) */[/color]

                  You're cheating ! :-)

                  public class test {
                  public static void main(String [] args) {
                  String a = "a string", b = "another one";
                  System.out.prin tln(a + b); // yes, I know you already know that :-)
                  }
                  } // Java - 1 ; C - 0... O:-)


                  --
                  "Je deteste les ordinateurs : ils font toujours ce que je dis, jamais ce
                  que je veux !"
                  "The obvious mathematical breakthrough would be development of an easy
                  way to factor large prime numbers." (Bill Gates, The Road Ahead)

                  Comment

                  • Richard Bos

                    #10
                    Re: What are OOP's Jargons and Complexities?

                    "Jirka Klaue" <jklaue@tkn.t u-berlin.de> wrote:
                    [color=blue]
                    > ITYM:
                    >
                    > #include <stdio.h>[/color]

                    And _I_ think you all mean: "Oops, we shouldn't have followed up to a
                    known kook and/or troll".

                    HTH; HAND.

                    Richard

                    Comment

                    • Stefaan A Eeckels

                      #11
                      Re: What are OOP's Jargons and Complexities?

                      On 23 May 2005 03:21:30 -0700
                      "Xah Lee" <xah@xahlee.org > wrote:
                      [color=blue]
                      > Ill-informed drivel[/color]

                      _______________ ____
                      /| /| | |
                      ||__|| | Please do |
                      / O O\__ NOT |
                      / \ feed the |
                      / \ \ troll |
                      / _ \ \ ______________|
                      / |\____\ \ ||
                      / | | | |\____/ ||
                      / \|_|_|/ \ __||
                      / / \ |____| ||
                      / | | /| | --|
                      | | |// |____ --|
                      * _ | |_|_|_| | \-/
                      *-- _--\ _ \ // |
                      / _ \\ _ // | /
                      * / \_ /- | - | |
                      * ___ c_c_c_C/ \C_c_c_c_______ _____


                      --
                      Stefaan
                      --
                      As complexity rises, precise statements lose meaning,
                      and meaningful statements lose precision. -- Lotfi Zadeh

                      Comment

                      • Tim X

                        #12
                        Re: What are OOP's Jargons and Complexities?

                        Morten Alver <morten@invalid .no> writes:
                        [color=blue][color=green]
                        > > ITYM:
                        > >
                        > > #include <stdio.h>
                        > > #include <string.h>
                        > >
                        > > int main(void)
                        > > {
                        > > char *a = "a string", *b = "another one", c[20];
                        > > puts(strcat(str cpy(c, a), b));
                        > > }
                        > >
                        > > /* ;-) */[/color]
                        >
                        > Just for the record, in Java you could write:
                        >
                        > String a = "a string", b = "another one", c = a+b;
                        > System.out.prin tln(c);
                        >
                        > All of this is irrelevant, the point is that the comparison by the OP is
                        > meaningless as an example of what OOP leads to.
                        >[/color]
                        The OP is a fool and well known to be one. Xah has a reputation for
                        posting flawed and incorrect information on a regular basis. I think
                        it was only last week he was claiming Perl didn't support lists and
                        today he is claiming that *everything* in Java is a class - unless
                        things have changed a lot since I escaped java 6 years ago, not
                        everything is a class - for example int, double and float do not have
                        to be classes (though they do have class versions as well). In fact, I
                        seem to remember in my initial reading concerning the design of Java
                        that it was decided that making everyting a class was a *bad idea*,
                        especially for arithmetic, which is why int, double, float are not
                        implemented as objects and that the object versions are included for
                        when you need interoperabilit y with class objects.

                        If you want a good laugh, visit Xah's homepage. He makes some
                        incredibly amusing claims and statements of 'fact' - as they say, on
                        the Internet, nobody knows your a dog!

                        Tim

                        --
                        Tim Cross
                        The e-mail address on this message is FALSE (obviously!). My real e-mail is
                        to a company in Australia called rapttech and my login is tcross - if you
                        really need to send mail, you should be able to work it out!

                        Comment

                        • alex goldman

                          #13
                          Re: What are OOP's Jargons and Complexities?

                          Tim X wrote:
                          [color=blue]
                          > If you want a good laugh, visit Xah's homepage.[/color]

                          He mentions that over a million people already visit it per year.

                          Comment

                          • xah@xahlee.org

                            #14
                            Re: What are OOP's Jargons and Complexities?

                            The Rise of “Static” versus “Instance” variables

                            In a normal programing language, variables inside functions are used by
                            the function, called local variables.

                            In OOP paradigm, as we've seen, super-subroutines (classes) are
                            assigned to variables (instantiation) , and the inner-subroutines
                            (methods) are called thru the variables (objects). Because of this
                            mechanism, what's once known as local variables (class variables) can
                            now also be accessed thru the assigned variable (objet) by design. In
                            OOP parlance, this is to say that a class's variables can be accessed
                            thru the object reference, such as in myObject.data=4 . For example:
                            mySurface = new a_surface();
                            mySurface.coord inatesList={... } // assign initial coordinates

                            However, sometimes a programmer only needs a collection of variables.
                            For exmple, a list of colors:
                            black = "#000000";
                            gray = "#808080";
                            green = "#008000";

                            In pure OOP, data as these now come with a subroutine (class) wrapper:
                            class listOfColors() {
                            black = "#000000";
                            gray = "#808080";
                            green = "#008000";
                            }

                            Now to access these values, normally one needs to assign this
                            subroutine (class) to a variable (instantiation) as to create a object:
                            myColors = new listOfColors(); // instantiation! (creating a "object")
                            newColor = myColors.black;

                            As a workaround of this extraneous step is the birth of the concept of
                            “static” variables. (with the keyword “static” in Java) When a
                            variable is declared static, that variable can be accessed without
                            needing to instantiate its class. Example:
                            class listOfColors() {
                            static black = "#000000";
                            static gray = "#808080";
                            static green = "#008000";
                            }
                            newColor = listOfColors.bl ack; // no instantiation required

                            The issue of staticality is also applicable to inner-subroutines
                            (methods). For example, if you are writing a collection of math
                            functions such as Sine, Cosine, Tangent... etc, you don't really want
                            to create a instance in order to use. Example:
                            class mathFunctions() {
                            static sin (x) {...}; // a static method
                            ...
                            }
                            print mathFunctions.s in(1); // no need to create object before use


                            The non-static variant of variables and methods are called “instance
                            variables” or “instance methods”, or collectively “instance
                            members”. Note that static members and instance members are very
                            different. With static members, variables and methods can be called
                            without creating a object. But more subtly, for a static variable,
                            there is just one copy of the variable; for instance variables, each
                            object maintains its own copy of the variable. A class can declare just
                            some variables static. So, when multiple objects are created from the
                            class, some variables will share values while others having independent
                            copies. For example:
                            class a_surface() {
                            static pi; // a static variable
                            coordinatesList ; // a instance variable
                            ...
                            };
                            a_surface.pi=3. 1415926; // assign value of pi for all
                            a_surface objects
                            mySurface1 = new a_surface();
                            mySurface1.coor dinatesList={.. .} // assign coordinates to one a_surface
                            object
                            mySurface2 = new a_surface();
                            mySurface2.coor dinatesList={.. .} // assign coordinates to another
                            a_surface object

                            The issues of static versus instance members, is one complexity arising
                            out of OOP.

                            ----------
                            to be continued tomorrow.

                            This is part of an installment of the article
                            “What are OOP's Jargons and Complexities”
                            by Xah Lee, 20050128. The full text is at


                            © Copyright 2005 by Xah Lee. Verbatim duplication of the complete
                            article for non-profit purposes is granted.

                            The article is published in the following newsgroups:
                            comp.lang.c,com p.lang.c++,comp .lang.lisp,comp .unix.programme r
                            comp.lang.pytho n,comp.lang.per l.misc,comp.lan g.scheme,comp.l ang.java.progra mmer
                            comp.lang.funct ional,comp.obje ct,comp.softwar e-eng,comp.softwa re.patterns

                            Xah
                            xah@xahlee.org
                            ∑ http://xahlee.org/

                            Comment

                            • Xah Lee

                              #15
                              Re: What are OOP's Jargons and Complexities?

                              The Rise of “Constructors ” and “Accessors”

                              A instantiation, is when a variable is assigned a super-subroutine
                              (class). A variable assigned such a super-subroutine is now called a
                              instance of a class or a object.

                              In OOP practice, certain inner-subroutines (methods) have developed
                              into specialized purposes. A inner-subroutine that is always called
                              when the super-subroutine is assigned to a variable (instantiation) , is
                              called a constructor or initializer. These specialized
                              inner-subroutines are sometimes given a special status in the language.
                              For example in Java the language, constructors are different from
                              methods.

                              In OOP, it has developed into a practice that in general the data
                              inside super-subroutines are supposed to be changed only by the
                              super-subroutine's inner-subroutines, as opposed to by reference thru
                              the super-subroutine. (In OOP parlance: class's variables are supposed
                              to be accessed/changed only by the class's methods.) Though this
                              practice is not universal or absolute. Inner-subroutines that change or
                              return the value of variables are called accessors. For example, in
                              Java, a string class's method length() is a accessor.

                              Because constructors are usually treated as a special method at the
                              language level, its concept and linguistic issues is a OOP machinery
                              complexity, while the Accessor concept is a OOP engineering complexity.

                              -----
                              to be continued tomorrow.

                              This is part of an installment of the article
                              “What are OOP's Jargons and Complexities”
                              by Xah Lee, 20050128. The full text is at


                              © Copyright 2005 by Xah Lee. Verbatim duplication of the complete
                              article for non-profit purposes is granted.

                              The article is published in the following newsgroups:
                              comp.lang.c,com p.lang.c++,comp .lang.lisp,comp .unix.programme r
                              comp.lang.pytho n,comp.lang.per l.misc,comp.lan g.scheme,comp.l ang.java.progra mmer
                              comp.lang.funct ional,comp.obje ct,comp.softwar e-eng,comp.softwa re.patterns

                              Xah
                              xah@xahlee.org
                              ∑ http://xahlee.org/

                              Comment

                              Working...