Overload Resolution of dynamic/object types

Last year sometime, I started doing some research about adding traditional overloads to PHP (you heard me, hehe). Basically I created a mechanism that allow devs to overload methods in PHP - which is quite interesting considering that we're talking about a loosely typed language - every variable essentially dynamic by default, minus type hinting

Sooo I remembered that C# 4.0 added similar logic to its codebase and decided to have a look at how C# resolves dynamic types within overloads.

Incidently the same can be said about the object type prior to C# 4.0, for intents and purposes the dynamic type is equivalent to object. eg. substitute dynamic for object prior to C# 4.0

Dynamic types does however get resolved at runtime, eg. late-binding (resolved by what the caller sent to it)

Lets have a quick look at my concerns, consider the following snippet:

 
using System;
 
namespace ConsoleApp
{
    class Program
    {
        static void f(Int32 x) { }
        static void f(dynamic x) {}
 
        static void f(Int32 x, dynamic y) {}
        static void f(dynamic x, Int32 y) {}
 
        static void Main(string[] args)
        {
            f(10); // Works
            f(10, 10); // Ambiguous - obvious
        }
    }
}
 

  1. Passing value 10 to method f, will resolve to (Int32 x) - we assume that (Int32 x) defines an exclusion from (dynamic x)?

  2. Passing values 10, 10 to method f, won't resolve - since its impossible to resolve, both methods are equally callable.

It seems pretty straightforward and we can see some kind of pattern... or can we?

Things get interesting as soon as we add a third parameter:
 
static void f(Int32 x, dynamic y, Int32 z) {}
static void f(dynamic x, Int32 y, dynamic z) {}
 

Building on our our previous assumptions, let's assume that x & z defines exclusions, by these assumptions, passing values 10, 10, 10 should resolve (Int32 x, dynamic y, Int32 z).

Instead, the compiler informs us that we made an ambiguous call - nullifying my previous assumptions.

Which brings me to what really happens (still busy confirming this with a few clever guys at microsoft), observe the following overloads (swapping the types of y & z of the previous example):
 
static void f(Int32 x, dynamic y, Int32 z) {}
static void f(dynamic x, dynamic y, Int32 z) {}
 

Passing values 10, 10, 10 will resolve correctly to (Int32 x, dynamic y, Int32 z), providing further clues to internal processes.

Resolving these overloads by hand, will look something like this:
  1. Cancel out matching types
  2. Cancel out least matching types eg if x is Int32 -> (Int32 > dynamic)
  3. In the end if we're not left with only one resolveable method, the methods are ambiguous
Another example:
At the end of the day, I can't fully agree with the resolution of dynamic/object types (regarding overloads) in C# - it is however a very safe design (good language design?).

But currently I would lean towards overload resolution like the following:
  1. Cancel out matching types
  2. Cancel out least matching types eg if x is Int32 -> (Int32 > dynamic)
  3. Cancel out methods containing less matching types eg. the second method only contains one definite match, but our first method contains two matches - hence more resolveable.
  4. In the end if we're not left with only one resolveable method, the methods are ambiguous

What do you guys and girls think? Any thoughts?






Post comment

Name *
Email
Title
Body *
Security Code
*
* Required fields

Latest Posts

Top 5 posts

Simple WYSIWYG Editor


Creating a WYSIWYG textbox for your website is actually quite simple.
2007-02-01 12:00:00

Moving items between listboxes in ASP.net/PHP example


Move items between two listboxes in ASP.net(C#, VB.NET) and PHP
2008-06-12 17:07:43

Cross Browser Issues: Firefox Word Wrapping


Firefox word wrapping issues
2008-06-09 09:51:21

Populate a TreeView Control C#


Populate a TreeView control in a windows application.
2009-08-27 16:01:03

What time will bring



2007-02-22 12:00:00