/* polymorphic linked list, first version (the conventional oop approach) */ using System; class cell { public readonly object head; // data (sometimes called item, datum, etc ...) public cell tail; // pointer to next cell public cell(object h, cell t) {head=h; tail=t;} // naturally polymorphic functions: public int length() { if (tail==null) return 1; else return 1+tail.length(); } // length /* C# (and now java too with jdk 1.5) has a nice feature called "boxing" and "unboxing". In old java, to interpret an integer (or scalar value) as an object, you must explicitly wrap it inside an object (using the Integer class). C# does this automatically. The following code is valid: int x = 2; object A = x; int y = (int)A; The wrapping and unwrapping of the integer is part of the type-casting procedure. Note that int, like everything else, is a subclass of "object" so casting from int to object is implicit. We can now create, for example, a list of integers using new cell(2,new cell(4,new cell(6,null))); and a list of strings with new cell("abc", new cell("def", null)); The length function, being "naturally" polymorphic (my term) can be written without any difficulty, since it never looks at the "heads". But what about other kinds of functions - that is, functions that are only polymorphic by virtue of procedures that abstracts out differences between classes. For example, how would one write a procedure to add up all the elements of a list. Here, polymorphism appears in a very different form, because the symbol "+" needs to be dispatched to one of several different procedures (integer addition, floating point addition, or string cat). Also, the return type must be "object" if we want to write it polymorphically, and before we apply the correct procedure, we need to first determine the "real"- that is, the runtime type of the objects. The special operator "is" (in java it's called "instanceof") allows us to test for the runtime type of objects. */ public object sum() { int axi = 0; // need accumulator for each type double axd = 0; string axs = ""; cell i = this; while (i!=null) { if (i.head is int) axi += (int)i.head; if (i.head is double) axd += (double)i.head; if (i.head is string) axs = axs+" "+(string)i.head; else throw new Exception("I don't know how to add that"); // (C# Exceptions are easier to use than Java's) } // while if (head is int) return axi; if (head is double) return axd; if (head is string) return axs; else return null; } // sum /* YIKES! That sure wasn't pretty compared to the length function. It also isn't pretty compared to what you might write in Perl: sub sum { my @L = @_; my $ax; foreach (@L) { $ax += $_; } $ax; } But Perl is an untyped language. Type safety is the responsibility of the programmer. If the above function is called with data for which "+" is not defined, then unpredictable and meaningless results will be returned (rather like with C++). The problem here, then, is to figure out a way to write functions such as sum in a more elegant way, AND STILL RESPECT THE OBJECT-ORIENTED TYPE SYSTEM. */ } // cell class