Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations derfloh on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Passing parameters - the whole object or just what I need?? 1

Status
Not open for further replies.

SBendBuckeye

Programmer
May 22, 2002
2,166
US
I am writing some generic procedures to spin through the forms collection. Should I write them to look for the whole object (eg me) or just what I need (eg me.controls) in the parameters. When passing objects, are they always by reference anyway? Are there any performance issues one way or the other?

I can do it either way, I just wondered if there is a preferred way.

Thanks for the help!

 
Your description of the generic functions is itself too generic for me to have a feel about whether it makes sense to use the form or a property/control parameter.

Object variables, like any other variables, can be passed either by reference or by value. The default depends on which version of Access you're using, so check your help file for ByRef and ByVal parameters in a Function or Sub procedure heading. However, the object that the parameter refers to is the same object as in the calling procedure, either way. It acts, then, as if it were a ByRef parameter. The difference only shows up if you Set the object parameter to something. If it's ByRef, it changes the object variable in the calling procedure; if it's ByVal, it doesn't.

Performance issues would depend on what the code in the generic function is doing, and how it is written. If you pass the form and the function is going to reference a control on the form very heavily, it would generally be slower than passing the control. But on the other hand, you could also write the function to use a local object variable that it initially Sets to the form's control, and then makes all references via the local object variable. Then the performance difference would be trivial.

In regard to code performance issues in general, my experience is that you very rarely need to be concerned about them. Modern computers and the VBA code is plenty quick enough that any suboptimal performance is likely to be dwarfed by the time it takes to access the data, let alone by the human reaction time. If you already have a programming background (and I'm sure you do, or you wouldn't even be thinking about performance), you already know not to put loop-invariant code inside a loop, for example. It's more productive to rely on these habits that have become second nature than to worry about optimizing the code as you're writing it. If you actually encounter a code performance problem, that's the time to look for ways to optimize it.

I used to write highly optimized assembler code for IBM mainframes. I'm SO glad we can now afford the luxury of writing code for CLARITY rather than SPEED! Rick Sprague
 
Thanks, Rick!

Here is the code. It locks or unlocks every control on the form based on the Boolean value I pass to the sub. The calling program is responsible for any exceptions. Is there any reason why I should modify this sub to pass me.controls to it instead of the me object as it is currently written? It is much easier to just pass me and let the sub worry about what it needs. I just wanted to make sure I wasn't missing anything.

************************* Begin Code ***********************

Sub LockFormControls(pobjMe As Object, pbooLock As Boolean)
Dim ctl As Control

On Error GoTo Err_LockFormControls

For Each ctl In pobjMe
ctl.Locked = pbooLock
Next

Exit_LockFormControls:
Exit Sub

Err_LockFormControls:

Select Case Err
Case 438
Resume Next
Case Else
MsgBox Err.Description & vbCrLf & Err.Number
Resume Exit_LockFormControls
End Select

End Sub

***************************** End Code *********************

Thanks for your insight!

 
Hmm. Does actually work if you pass it Me? I can see that it might, but I haven't coded quite this way.

I actually DO have an objection to this routine that's based on performance. You have declared the first argument as type Object. For performance reasons, you should always avoid using the Object class any time you can. (I'll explain below.) For this case, I would recommend that you declare pobjMe as type Form, change the For statement to "For Each ctl In pobjMe.Controls" (it may work the way it is, but this is clearer), and pass it Me.

You may have seen the terms "early binding" and "late binding." Early binding occurs at compile time, and it means that the compiler has enough information to determine exactly what kind of object an expression will resolve to at run time. This allows the compiler to generate code that is specific for that type of object.

In contrast, late binding occurs at run time, and means that it's possible for an expression to resolve to different types of objects. It's less efficient, because the compiler has to generate code that tests what kind of object it is, kind of like a Select Case statement, and to run a different piece of code for each possible type of object. In the extreme case, the type of object at run time could even be a type the compiler knew nothing about at all (an ActiveX object, for instance), and the compiled code then has to, in effect, ask the object if it knows how to <something> (whatever is necessary for how you've used it in the expression). This involves a lot of work, with table lookups and such, so that your program and the object can learn how to communicate with each other dynamically at run time. As you can guess, this is a relatively slow process, and if you do it in a tight loop will slow it down quite significantly. So late binding should be avoided whenever possible.

When you use the Object type, you're basically asking for late binding. You're telling the compiler that the argument is an object, but it could be any kind of object, even one the compiler doesn't know about. The compiler has to generate code, for the For Each statement, that asks the object at run time what kind of object it is, and what properties and methods it has. The run time code then looks to see if the object is a Collection. If in fact you've passed it Me (a Form object), the run time code will see that it's not a Collection, and will then look for the default property, which for a Form object is Controls, which IS a kind of Collection. Then the run time code has to look for a _NewEnum method (an internal method of Collection objects that is needed by the For Each statement). It will find it, and at that point the run time will go back to executing your For Each loop. That's a lot of overhead! And it will occur each and every time you call your function.

If you declare the argument as type Form, all that lookup can occur at compile time instead, and occurs only once. The generated code won't have to look anything up at all, because the compiler will already have figured out where the properties and methods are (well, sort of; it actually figures out a fast way to locate them at run time).

You could also declare the argument as type Controls (the actual type of the Form.Controls property), and pass it Me.Controls. The compiled code would have been virtually identical, and just as fast, as using type Form. I recommended using Form because you preferred it to Controls, and there is no significant difference in performance.

But the important thing is, either Form or Controls is vastly better than using Object as an argument type. You should always try to use as specific an object type as possible (such as TextBox and Form_MyForm), and reserve the generic ones (such as Object, Form, and Control) for when you really need them.

Even if you have to use a generic type, such as Form--you do in this case, because you want to pass different forms to your routine--you can still get early binding by using only the properties and methods of the type you specify. Thus, pobjMe.Controls will be early bound. You'll only get late binding if you use a property or method that the compiler doesn't know about.

You can tell whether the compiler knows about it when you type the VBA code; if the compiler knows about it, it will give you the list of properties and methods when you type the &quot;.&quot; after the object reference. If it doesn't give you the list, or if you type a property or method that's not on the list, you can expect late binding for that expression.

What makes the Object type so bad is that it has (essentially) no properties or methods. That means that any property or method call to an object variable or argument declared as Object will be late bound. Rick Sprague
 
Thanks, Rick! That's why I love this site. I'm new to Access and have only been on this site a couple weeks and you get deep, in-depth answers explained in a way you can understand.

I will change the code to pass me.controls and change my first parameter to type controls.

Thanks also for the lesson on early vs late binding. I had seen the term but hadn't yet actually had to deal with it. Your explanation makes perfect sense and will save me some problems down the road.
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top