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?
Some research and a better reading of the earlier referred to article mentioned by Hans Passant, brings about the following conclusion:
IDynamicMetaObjectProvider
if you want to explicitly support dynamics, the VB.NET compiler is updated to recognize that;Object
will only use the DLR and method caching if the object implements IDynamicMetaObjectProvider
;IDynamicMetaObjectProvider
, using Object
on such types or your own types will invoke the classical, non-cached VB.NET late-binder.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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With