Early binding versus late binding
When referring to objects in programming code, there are two terms that you may hear being used frequently to describe how the reference is made to those objects – early binding and late binding.
In this article, we’ll look at these two terms, at how the concepts impact on the way you write your code and the way your code executes.
Firstly, definitions. Microsoft defines the difference as follows:
An object is early bound when it is assigned to a variable declared to be of a specific object type. By contrast, an object is late bound when it is assigned to a variable declared to be of type Object. Objects of this type can hold references to any object, but lack many of the advantages of early-bound objects
In other words, if an object variable is defined and instantiated as such:
Dim objExcel as object
Set objExcel = CreateObject(“Excel.Application”)
then it counts as late bound, whereas defining and instantiating it in this way:
Dim objExcel as Excel.Application
Set objExcel = New Excel.Application
counts as early bound.
In the above article, Microsoft go on to say
You should use early-bound objects whenever possible, because they allow the compiler to make important optimizations that yield more efficient applications. Early-bound objects are significantly faster than late-bound objects and make your code easier to read and maintain
Elsewhere, Microsoft go as far as to claim that
In terms of overall execution speed, [early binding] is at least twice as fast as late binding.
So that’s that then. Microsoft have spoken, so it must be true. And for the large part, it probably is true – given the choice, early binding has siginificant benefits over late-binding, both for code efficiency and ease-of-use. But notice the little caveat – “Whenever possible…” So when would you use late binding? When is it not possible to use early binding?
The first step in using early binding is to ensure that the compiler “knows” about the object to which you want to bind. If you are working with a form in Access, then the controls in the toolbox are all known, or intrinsic, objects, and you can create references to them without any concern. Code such as
Dim tb as TextBox, cbo as ComboBox, lbl as Label, frm as Form
will compile without problem, and these are said to be early bound. Note that it’s also possible to create a variable to point to a specific form, with code such as
Dim frm as Form_frmOrders
and this too is early binding. However, within the context of this discussion, binding in this way is no different to declaring a variable “As Form”. In fact Access (and Visual Studio) create a custom class based on any form you design, and so in this example Form_frmOrders is a class in the same way that Form is a class, and an object variable declared as either one is still early bound. (This is only true of forms – you cannot, for example, declare a variable As txtFirstName, should you have such a control – it’s simply an instance of a class, rather than a class in its own right.)
Note: When we say that the compiler “knows” about an object, what do we mean? Well, when referring to an object programmatically yields Intellisense help (that is, you can type a dot after the object name and get a list of properties and methods), this is because the compiler is aware of a list of functions that the declared object supports, and where to locate those functions in memory. This information is located in the object’s “v-table” – an index of members of an object’s interface, along with pointers which can be resolved at run-time to the exact location for the code to be executed. If this v-table isn’t available, that resolution of the available properties and methods, and their locations in memory have to be resolved at run-time. The reason why this is so much slower is that a call to such a member is a two-stage process; the first call requests an ID for a given method of the unknown “object” type, which returns a memory pointer, the second call is to that memory location in order to invoke the method or property.
However, not all objects are immediately visible to the compiler. There may be times when you want to create some form of external object – a recordset, an Excel workbook, or a Word Document for example. If you simply write code that attempts to reference such an object along the lines of
Dim xlApp as Excel.Application
the compiler will reject your reference as an unknown user defined type
In all these cases, you have to create the reference first, if you want to use early binding. This is done by selecting References from the Tools menu, and ticking the desired reference. In order to create a reference to Excel, for example, I’d tick the Microsoft Excel 12.0 Object library:
Now the compiler (and so the IDE) will know about all the classes (through its v-table, as per the note box above) and members listed in the Type library (.tlb), object library (.olb) or executable (.exe) file, and object variables created of type Excel.Application (in our above example) will work successfully.
With late binding, the code does not make an explicit reference to the type of object when the variable is declared. Instead, it will simply use the “Object” type:
Dim xlApp as Object
This allows for any object to be instantiated at run-time, giving great flexibility. However, it also means that the work needed to locate the precise method being called, or access the specific property being referenced, must now be done at run-time, which, of course, slows down the execution.
But this is not the only problem with late binding. Because at design time the compiler cannot know what kind of object will be instantiated, it cannot offer any help with properties and methods – rendering intellisense unavailable. With early bound objects, typing the object variable’s name and a dot results in this:
whereas with late bound objects, you’re more likely to see this type of help:
Furthermore, pressing F2 will bring up the object-browser, listing all known members of all known objects. And of course, with late bound object variables, there are no known members until the call is made at run-time to an actual object. This means that not only is the intellisense help unavailable, but all the documentation from the Object Browser is also unavailable.
It would seem, then, that the case is cut and dried – early binding good, late binding bad.
But what of those situations mentioned right back at the start of the article, where only late binding is possible. What are these situations? And what exactly is the penalty incurred in execution efficiency?
When to use late binding
Looking at the References dialog box above, it can be seen that a reference has been made to Microsoft Excel 12 – aka Excel 2007. But what if I need to create an application which can be used be people who don’t have Excel 2007? The reverse situation is less problematic – if I develop an application referencing Excel 2000, it should be happily usable by those with Excel 2000, 2002 (XP), 2003 and 2007 because the application should automatically “upgrade” the reference to match the available version. But no matter how clever those people at Microsoft may be, they’ve yet to find a way to make an application created in 2000 know what’s going to be going on in 2007.
In such a situation, the only solution is to use late binding. Declare the object variable “as Object” and then instantiate it through the use of “CreateObject”. When you refer to the variable from this point on, do so in the usual way, invoking properties and methods as needed. Because there won’t be any help available, you’ll need to be VERY careful with your syntax, and ensure that those methods and properties that you are used to calling on your version of Excel (or whatever) were actually available in the days of Excel 2000.
Provided you’ve worked with care, and ideally tested the application on a machine running only the older version of the referenced component, you should be okay. But what of the loss of efficiency? Is this a major concern?
The efficiency of early binding over late binding
Given Microsoft’s warnings that late binding can be twice as slow as early binding, I was interested to see exactly how big the impact of late binding would be.
In this test, I’ve created two routines which are identical, except that one variable is declared using As Object, the other using As ADODB.Recordset, having set a reference to Microsoft ActiveX Data Objects 2.8. I chose to use ADO’s recordset object because I didn’t want to add the overhead of managing significant display-related variables which could have distorted the result if I’d decided to create (and show) something like Excel.
I also decided to actually “do” something with the object, rather than simply create it and then destroy it. Of course, this introduces other elements (reading from a database and thus the hard disk, primarily) but as long as those other elements remain fixed, I felt that this would be a more accurate representation of a real life scenario.
To that end, the code creates an ADO recordset object based on a SQL statement. It uses the default forward-only, read-only settings, and then loops through the records (2155 of them) before closing the recordset and setting the variable back to nothing. Here’s the code:
In order to test this, I’m using the TimeGetTime API call because of its vastly superior accuracy compared to the VBA Timer function. I’ve also used a bit of automation of Excel, so that we can get a nice log which will be easy to analyse:
The results are quite interesting – and certainly don’t reflect the “twice as fast” claim in the Microsoft documentation. Again, this is not to say that Microsoft’s documentation is inaccurate, but reflects that in a “real-world” environment, the differences are likely to be much smaller.
The results are below. All values are in milliseconds:
As you can see, in practice, the late binding code produced a result which was on average 17.44% slower than the early binding code. Not perhaps as significant as we might have been let to believe by the articles on MSDN, but certainly a significant percentage. But of course, percentages can be misleading; if one person in the world dies in a freak accident caused by a falling gargoyle, then 10 years later another couple of people do, we can claim that gargoyle-related deaths have doubled in ten years… But at its worst, this spate of gargoyle destruction claimed the lives at a rate of (assuming a world population of 6.5 billion) 0.00000003% !!
In fact, the late binding caused our code, which was pretty simple (no editing of data, for example) to take an extra 2.27 milliseconds to run.
Would you notice 2.27 milliseconds? I doubt it. And in very many cases, that’s all it would be. You create an object, you use it, you destroy it. Once.
But put this into a loop that runs a thousand times, and already we’re up to counting in seconds – a delay which is definitely noticeable. If there’s any chance that your late-binding code might end up being invoked inside a loop, then it may be worth looking to re-write it and make it that bit more efficient.
It is, though, more likely that the efficiency of running the code will be one of the last issues of concern. Writing the code without any help because it’s late bound, making intellisense and the Object Browser unavailable is much more likely to result in errors, and the compiler won’t be able to flag these up at design time. If trying to resolve these problems results in half an hour of extra work, then that’s a lot of bundles of 2.27 milliseconds; the drop in efficiency is most definitely noticeable here.
For that reason alone, early binding should always be the first-choice solution. Late binding is necessary when you’ve no choice but to write code which will be backward compatible (ie with earlier versions of the objects you’re coding), but that’s probably about the only time you’ll use it for real.
Now… better go re-write my late binding calls to Excel in the code above!
Remember, if you’d like to get more out of Microsoft Access, why not let us show you how on a customised Access training course?