That's the best example I know of. You have two numbers - you want to add them - but adding a couple of ints is different from adding an int and a float, or an int and a fraction (fractions are first class numbers in ST) or adding an int and a point....
In Java a small subset of what ought to be implemented in Number would look like:
class Number
{
Number add(Number n);
Number addInteger(Number n);
Number addFloat(Number n);
int intValue();
float floatValue();
}
class Integer extends Number
{
Number add(Number n) { n.addInteger(this); }
Number addInteger(Number n) { return new Integer(n.intValue() + this.intValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}
class Float extends Number
{
Number add(Number n) { n.addFloat(this); }
Number addInteger(Number n) { return new Float(n.floatValue() + this.floatValue()); }
Number addFloat(Number n) { return new Float(n.floatValue() + this.floatValue()); }
}
So if I have a pair of Integers
Number n1 = new Integer(3);
Number n2 = new Integer(5);
Number n3 = n1.add(n2);
calls:
n1.add(n2) // neither concrete type is known here - within this call n1 (an integer) will identify its concrete type to n2
n2.addInteger(n1) // by telling it to addInteger to itself - n2 knows its type and does the right thing
Its very slick but the number of methods does indeed grow exponentially with the number of types. So its only really practical up to maybe 10 types or so.