In VBA, there are several features that allow us to do things that may not be checked at the compile time. In particular, it is possible to write several late-bound expressions which means that it can potentially contain run-time errors. One common misconception about late-binding is that it’s a matter of adding a reference and using the referenced library. However, this is still late-bound:
1 |
Forms!frm_application!frm_Loan.Form!loans_DateDocsIssued.Requery |
and so is this:
1 |
Forms("frm_application").frm_Loan.Form.loans_DateDocsIssued.Requery |
Why are they late-bound? The basic problem is that various members such as the Forms() function, the Form property, the Controls collection all return a generic object — Access.Form in the first 2 cases and Access.Control in the last case.
Both Access.Form and Access.Control has a number of members that we can use, and in this case, Requery is one such member that exists. Thus, we can avoid the late-binding by using this:
1 |
Forms("frm_application").Controls("frm_Loan").Form.Controls("loans_DateDocsIssued").Requery |
The key difference is that for each step of . you access, you still get an Intellisense dropdown showing you available members. In the earlier example, the Intellisense would stop working as soon as you accessed the frm_Loan, because that is not a member that exists on the Access.Form class. You can see the difference on the object browser for Access.Form object.
Contrast this to any specific form classes in the current project (the project being called Default):
Note that Form_frmLogin has all the Access.Form members and has its additional members exposed. In the example of Requery, the member exists on both Access.Form and Form_application. That is also true for the Access.Control and loans_DateDocsIssued as well.
However, if we wanted to be more specific and access things like Rowsource that might not exist on the generic Access.Control interface, then we need to cast them using the specific objects. One way to do this is:
1 2 3 4 5 6 |
Dim frmApplication As Form_frm_application Dim frm_Loan As Form_frm_Loan Set frmApplication = Forms("frm_application") Set frm_Loan = frmApplication.frm_Loan.Form frm_Loan.loans_DateDocsIssu and wed.Requery |
Note that on the line 4 and 5, we perform a cast away from Access.Form that is returned by both Forms() function and the Form property into the specific class (e.g. Form_frm_application and Form_frm_Loan, respectively.
Since we have the Form_frm_Loan, it already knows about the control loans_DateDocsIssued and whether it’s a Access.Textbox or Access.Combobox rather than simply just Access.Control, enabling us to access all the properties, and more importantly have the Intellisense available at every stop.
The lack of Intellisense when you press . is a surefire sign that you are dealing with late-bound code which also means that you cannot verify this. This is a bug time bomb because it can’t be checked until you run it and that adds more testing burden to your application. Why create errors that can only be seen at runtime? It is much preferable to ensure that errors are caught at the compile time, saving time. By consistently using early-bound code, we can help reduce the number of potential runtime error times and thus deliver a better quality codebase.