views:

174

answers:

3

Some people have argued that the C# 4.0 feature introduced with the dynamic keyword is the same as the "everything is an Object" feature of VB. However, any call on a dynamic variable will be translated into a delegate once and from then on, the delegate will be called. In VB, when using Object, no caching is applied and each call on a non-typed method involves a whole lot of under-the-hood reflection, sometimes totaling a whopping 400-fold performance penalty.

Have the dynamic type delegate-optimization and caching also been added to the VB untyped method calls, or is VB's untyped Object still so slow?

A: 

Good question. I'm guessing the answer is "No", because this article in MSDN magazine says VB.Net has been changed to support the Dynamic Language Runtime, and briefly describes changes to the runtime but doesn't mention caching.

Does anyone know better?

MarkJ
+2  A: 

Quoting from the what's new article:

Visual Basic 2010 has been updated to fully support the DLR in its latebinder

Can't get more explicit than that. It is the DLR that implements the caching.

Hans Passant
I noticed that line too and I like your reading of the sentence. To really know whether the support is equal, I guess we're up to testing, reverse engineering the IL and measuring the performance.
Abel
If that's what floats your boat, go for it. Or you could just use C# if you think it does a better job. Don't you have bigger problems to worry about?
Hans Passant
@Hans: not really helpful to tell someone who drives a Fiat to go buy a Mercedes, let alone rebuild the Fiat into a Mercedes, even though in some situations the Mercedes may drive better. I have customers that do C#, VB, PHP, Java, Perl, Ruby etc. Fortunately, I can tell my customers that we look for the best solutions in their own language.
Abel
@Abel: your Fiat got a 5 liter V6 engine. Not really sure what you are looking for.
Hans Passant
@Hans: I'm sure you understand, but thanks for checking back. A more elaborate answer to your question (and the original q.) is added to the thread, perhaps that sheds some light on the questions you were asking yourself.
Abel
+5  A: 

Solution

Some research and a better reading of the earlier referred to article mentioned by Hans Passant, brings about the following conclusion:

  • VB.NET 2010 supports the DLR;
  • You can implement IDynamicMetaObjectProvider if you want to explicitly support dynamics, the VB.NET compiler is updated to recognize that;
  • VB's Object will only use the DLR and method caching if the object implements IDynamicMetaObjectProvider;
  • BCL and Framework types do not implement IDynamicMetaObjectProvider, using Object on such types or your own types will invoke the classical, non-cached VB.NET late-binder.

Background: elaborating on why late-binding caching could help VB code performance

Some people (among whom Hans Passant, see his answer) may wonder why caching or non-caching in late-binding could possibly matter. Actually, it makes a large difference, both in VB and in other late-binding technologies (remember IQueryInterface with COM?).

Late-binding comes down to a simple principle: given a name and its parameter-declarations, loop through all the methods of this class and its parent classes by means of methods available though the Type interface (and in VB, a method, a property and a field can look the same, making this process even slower). If you consider that method tables are unordered, then this is easily much more expensive than a single direct (i.e., typed) method call.

If you were capable of looking up the method once, and then storing the method-pointer in a lookup table, this would greatly speed up this process. Cached method binding in the DLR goes one step futher and replaces the method-call with a pointer to the actual method, if possible. After the first call, this becomes an order of magnitude faster for each subsequent call (think 200x to 800x times faster).

As an example of when this matters, here's some code that illustrates this issue. In a case where every class has a .Name string property, but the classes do not share a common ancestor or interface, you can naively sort lists of any of those types like so:

' in the body of some method '
List<Customers> listCustomers = GetListCustomers()
List<Companies> listCompanies = GetListCompanies()

listCustomers.Sort(MySort.SortByName)
listCompanies.Sort(MySort.SortByName)

' sorting function '
Public Shared Function SortByName(Object obj1, Object obj2) As Integer
    ' for clarity, check for equality and for nothingness removed '    
    return String.Compare(obj1.Name, obj2.Name)    
End Function

This code (similar at least) actually made it into production with one of my clients and was used in an often-called AJAX callback. Without manually caching the .Name properties, already on medium sized lists of less than half a million objects, the late-binding code became such a noticeable burden that it eventually brought the whole site down. It proved hard to track down this issue, but that's a story for another time. After fixing this, the site regained 95% of its CPU resouces.

So, the answer to Hans's question "don't you have bigger problems to worry about" is simple: this is a big problem (or can be), esp. to VB programmers who have gotten too careless about using late-binding.

In this particular case, and many like them, VB.NET 2010 has apparently not been upgraded to introduce late-binding, and as such, Object remains evil for the unaware and should not be compared with dynamic.

PS: late-binding performance issues are very hard to track down, unless you have a good performance profiler and know how late-binding is implemented internally by the compiler.

Abel
+1 for the detailed explanation!
Eyvind