Automation

In COM Automation the client communicates with the COM server through the IDispatch interface and data types have to be 'marshalled'. IDispatch uses the Invoke() method to call the remote method. Invoke must be generic enough to accept any number and any type of variables; thus the parameters it accepts are a string containing the method name to be called and an array of arguments. This array is an array of Variants and although each array element might be of a different internal type it does not matter; the array is still homogeneous since each element is wrapped up as a variant.

So by using a variant you get the best of both worlds : can call Invoke to pass a generic structure in a standardized way but also get run time type safety at the same time because of the internal tag. It balances between the untyped and typed world which brings us to the subject of delegates or type-safe pointers.

.NET and Delegates

A delegate is .NET's implementation of a type safe function pointer. It is an actual type and comprises a few members; one of them surprisingly is an Invoke() method. When you say :

public delegate int MyDelegate ( string a, int b );

the compiler actually expands to this :

public class MyDelegate : System.MulticastDelegate

{ public double Invoke( string a, int b); . . . }

An instance of that delegate cannot point to a method that has a different signature than itself

The difference with COM+ IDispach Invoke (well not the only one) is that it is type safe since it contains the exact signature of the method to which it is tied and is checked for it at compile time.

But, guess what, there is a method called Delegate.DynamicInvoke which allows for late binding of delegates and acts as an IDispatch Invoke().

DynamicInvoke takes, instead of an array of Variants, an array of Objects and returns an object instead of matching the signature of the underlying method:

del.DynamicInvoke( new object[] { 1, 2 });

This brings us back to the example of the generic function that must take any number and type of arguments, and also to the similarities between Objects and Variants. An Object can hold any type but instead of having an internal associated tag it keeps a full Metadata table with much more details.

The downside is that invoking the delegate like that is not type safe. The caller can Invoke the delegate with the wrong parameters and you'll get an exception at runtime.

Other subjects related to .NET and types are Generics that provide custom made type safe collections (not only) and type inference (used extensively by Linq where a lot of times you cannot use explicitly typing, so you let the compiler decide)

Summary

The line between strongly typed and dynamically typed languages is getting blurred as time progresses.Strongly typed languages tend to become more dynamic as the C# example demonstratesand dynamically typed ones tend to become more static as in Perl6. In both cases they strive to hold on to the advantages offered by the predefined type system and add further capabilities offered by another type system.

Modern and evolving requirements require the compile time safety provided by the static system and at the same time the flexibility provided by the dynamic system

The static system allows for type safety, early error detection, unit testing and improved performance.

The dynamic system allows for flexibility by throwing type safety away, rapid prototyping and easier interop/'gluing' between heterogeneous components with a trade off in performance.

For this reason it is essential to understand how each type system works so not be sidetracked by each system's 'annoyances' and intricacies but start enjoying the goods that each system can offer, leading to more productive coding.