Consider the following code example:
interface IA
{
function foo(s:String):void;
}
interface IB
{
function foo(i:int):void;
}
class AB implements IA, IB
{
public function foo(s:String):void {}
public function foo(i:int):void {}
public function foo(u:uint):void {}
public function foo(n:Number):void {}
public function foo(o:Object):void {}
}
Now imagine we have a modified version of the compiler that supports method
overloading. AB compiles to:
class AB ->
foo_String_void -> String -> void -> {}
foo_int_void -> int -> void -> {}
foo_uint_void -> uint -> void -> {}
foo_Number_void -> Number -> void -> {}
foo_Object_void -> Object -> void -> {}
There are problems with this. First the compile time problems:
class TestAB
{
public function testFoo():void
{
var ab:AB = new AB();
ab.foo(1); // <- which foo does this call? int, uint or Number?
ab.foo(null); // <- and this one? String or Object?
ab["foo"](""); // <- how do we map this to ab.foo_String_void() ?
}
}
Then there are runtime problems:
class TestIA
{
public function testFoo():void
{
var ab:AB = new AB();
callFoo(ab, "");
var name:String = "foo";
ab[name](""); // <- how do we map this to
ab.foo_String_void() ?
}
private function callFoo(reference:IA, value:String):void
{
reference.foo(value); // <- how do we map foo to foo_String_void?
}
}
I think the first problem (which method to use when the data is ambiguous)
can be solved by a set of simple rules. I think the other problems could be
solved if we modify what AB gets compiled to:
class AB ->
foo_String_void -> String -> void -> {}
foo_int_void -> int -> void -> {}
foo_uint_void -> uint -> void -> {}
foo_Number_void -> Number -> void -> {}
foo_Object_void -> Object -> void -> {}
foo -> Object -> void ->
{
if (p1 is String)
{
call foo_String_void, p1
}
...
}
We put in place a catch-all foo that handles all the situations where the
compiler cannot work out the mapping at compile time.
Thoughts?
David.