By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,346 Members | 2,331 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,346 IT Pros & Developers. It's quick & easy.

Tricky VB/VBA side effects, and how to avoid them

P: n/a
== On Error Resume next, and Err.Number ==

If you want to call one of your procedures from another procedure, and check
for errors afterward, you mayimagine that you should write code something like
this...

On Error Resuse Next
MyFoo 123
lngErrNum = Err.Number
On Error Goto 0

.... so you do that, and it seems to work. A while later, you add code inside
MyFoo that does something similar, and now you find that the code above
sometimes detects an error when it shouldn't. This is because sometimes, the
error information never does get cleared after the error is skipped in the
called procedure, so it's still there when the calling procedure checks it.

I recommend engineering out this possibility at both ends. First, always do
an explicit Err.Clear after an "On Error Resuse Next" section, and second,
always trap for the occurrence of errors in calls to other procedures in the
same project using On Error Goto <label>, not On Error Resume Next, in spite
of the extra code involved.

== Passing object values to Variant parameters of procedures ==

Let's say you have a procedure that takes a Variant as a parameter, and adds
the parameter value to a collection. Now, let's say you call that procedure
from code in a form, and pass it, say, Me!txtName as an argument, then close
the form. Later, when you try to read the value back out of the collection,
you get an error. Why?

For convenience, VB allows certain objects to behave as values when you treat
them as values and as object references when you treat them as object
references, thus I can say either strName = Me!txtName to get the value from
the control, or Set ctlName = Me!txtName to make a reference to the control.

When you pass an object as a Variant parameter, there is nothing about the
syntax that tells VB whether to use the value or the object refence, and it
will always use the object reference in this case. This works fine only so
long as the procedure either expects an object, or does something internally
that causes the value interpretation of the object to be used while the
object's state is still valid.

This problem is really insidious since it can cause procedures to break after
a change that seems inconsequential, and can cause code to work some
circumetances, and not in others (e.g. work in testing, and fail when you demo
to the customer).

Again, I recommend solving the problem at both ends, just to cover all your
bases. When you want to pass the value of an object to a procedure, be
explicit about it, and pass something like Me!txtName.Value. When writing a
procedure that takes a variant and needs to deal only with a value, not an
object reference, convert any object reference you get to a plain value.

Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...

== Passing object references ByVal vs ByRef ==

Given the issue above, you may think you can solve the problem by defining
your function parameters as ByVal. That should always get the value of the
object, not the object reference, right? Wrong.

There are actually 2 levels of metaphor going on here.

First, for parameters that are passed by "reference", the function uses an
indirect reference back to the variable in the calling procedure, so the
entire item does not have to be copied (a good thing for a string or an
array), and so that any changes made to the "value" (more on this below)
affect the value of the variable passed to the procedure in the calling code
as well.

Second, there are object type variables that have "references" to object
instances stored in memory, but these are -not- the same thing ByRef means by
"references".

It turns out that what it actually means to pass an object variable by
reference or by value is that if you pass it by reference, assigning the
parameter variable a reference to a new object instance affects the variable
in the calling procedure as well, so that it now also points to the new object
instance.

When passing by value, a separate, new reference to the same object instance
is created in the called procedure, so that changes made to the state of the
instance are still shared between the caller and called procedure (the 2
references are to the same instance), but assigning a new instance to the
parameter variable within the called procedure does not also affect the
variable in the calling procedure (the 2 references are now to different
instances).

== ByRef and side effects ==

Parameters in VB/VBA are ByRef if you don't specify, and that means that a
change made to the parameter in a called procedure affect the calling
procedure. No new news here. What that means, though, is that you really
have to be careful because it's common to use a parameter as a variable with
an initial state that can then be changed as part of the procedure's process.
if you don't remember to make the parameter ByVal, you just accidentally
mangled a value in the calling procedure, and this kind of bug can be really
tricky to track down.

I recommend yet another 2-pronged attack on this problem. First, always
specify ByVal for any parameter that has no specific, good reason to be ByRef
(and performance is only a good reason when you are having or expect to have
an actual performance problem). Second, never, ever assign a value to a
parameter variable unless it actually is for the purpose of returning a value
to the calling procedure through a ByRef parameter. In all other cases, use
local Dim'd variables for any values that can be changed during the execution
of the procedure.
Nov 13 '05 #1
Share this Question
Share on Google+
13 Replies


P: n/a
Steve Jorgensen <no****@nospam.nospam> wrote in
news:7s********************************@4ax.com:
Again, I recommend solving the problem at both ends, just to cover
all your bases. When you want to pass the value of an object to a
procedure, be explicit about it, and pass something like
Me!txtName.Value. When writing a procedure that takes a variant
and needs to deal only with a value, not an object reference,
convert any object reference you get to a plain value.

Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...


Does putting () around an object cause the evaluated value to be
passed?

Wouldn't using ByVal fix the problem, too, assuming you don't want
to operate on the value itself (which you wouldn't really be able to
do with .Value, anyway)?

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 13 '05 #2

P: n/a
Steve Jorgensen <no****@nospam.nospam> wrote in
news:7s********************************@4ax.com:
== Passing object references ByVal vs ByRef ==

Given the issue above, you may think you can solve the problem by
defining your function parameters as ByVal. That should always
get the value of the object, not the object reference, right?
Wrong.

There are actually 2 levels of metaphor going on here.

First, for parameters that are passed by "reference", the function
uses an indirect reference back to the variable in the calling
procedure, so the entire item does not have to be copied (a good
thing for a string or an array), and so that any changes made to
the "value" (more on this below) affect the value of the variable
passed to the procedure in the calling code as well.

Second, there are object type variables that have "references" to
object instances stored in memory, but these are -not- the same
thing ByRef means by "references".

It turns out that what it actually means to pass an object
variable by reference or by value is that if you pass it by
reference, assigning the parameter variable a reference to a new
object instance affects the variable in the calling procedure as
well, so that it now also points to the new object instance.

When passing by value, a separate, new reference to the same
object instance is created in the called procedure, so that
changes made to the state of the instance are still shared between
the caller and called procedure (the 2 references are to the same
instance), but assigning a new instance to the parameter variable
within the called procedure does not also affect the variable in
the calling procedure (the 2 references are now to different
instances).


Steve, I don't understand this -- I can't quite get your point.

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc
Nov 13 '05 #3

P: n/a
On Wed, 01 Sep 2004 19:17:05 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Steve Jorgensen <no****@nospam.nospam> wrote in
news:7s********************************@4ax.com :
Again, I recommend solving the problem at both ends, just to cover
all your bases. When you want to pass the value of an object to a
procedure, be explicit about it, and pass something like
Me!txtName.Value. When writing a procedure that takes a variant
and needs to deal only with a value, not an object reference,
convert any object reference you get to a plain value.

Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...
Does putting () around an object cause the evaluated value to be
passed?


Yes, but that reads strangely when you are only passing one parameter. If
it's a Sub call, it looks like you put in parenthes that don't belong there,
and if you call a function, it looks liek you have an extra set. Either way,
you or someone else maintaining the code might end up taking them out later.
Wouldn't using ByVal fix the problem, too, assuming you don't want
to operate on the value itself (which you wouldn't really be able to
do with .Value, anyway)?


In another section of my post, I tried (not very well, apparently) to explain
why it turns out that it would not, though I've only understood this for a
short time, myself. When objects are involved, ByVal is misnamed, because it
doesn't force the object's value to be evaluated, it just makes a new
reference to the object instead of sharing the calling procedure's reference
to the object.

If that makes sense, then it answers the question in your other post as well.
Perhaps, an example would help, though.

Let's assume my form has controls txtValue1, containing "aaa" and txtValue2
containing "bbb". The following code doesn't resemble anything you would
actually do, but it illustrates the behavior I'm trying to explain.

First, here's the output from the code below...

txtValue1=aaa txtValue2=bbb
txtValue1=aaa txtValue2=xxx
ctl.Name=txtValue2
txtValue1=yyy txtValue2=zzz
ctl.Name=txtValue2

Now, the code...

Private Sub Foo()
Dim ctl As Access.Control

Debug.Print "txtValue1=" & Me!txtValue1, _
"txtValue2=" & Me!txtValue2

Set ctl = Me!txtValue1
Bar ctl
' Me!txtValue2 now contains "xxx"
' ctl now contains a reference to Me!txtValue2
Debug.Print "txtValue1=" & Me!txtValue1, _
"txtValue2=" & Me!txtValue2
Debug.Print "ctl.Name=" & ctl.Name

Set ctl = Me!txtValue2
Baz ctl
' Me!txtValue1 now contains "xxx"
' ctl still contains a reference to Me!txtValue2
Debug.Print "txtValue1=" & Me!txtValue1, _
"txtValue2=" & Me!txtValue2
Debug.Print "ctl.Name=" & ctl.Name

End Sub

Private Sub Bar(varValue As Variant)
' Because parameter is by reference, the next line changes
' what control the calling code's parameter variable points
' to as well.
Set varValue = Me!txtValue2
varValue.Value = "xxx"
End Sub

Private Sub Baz(ByVal varValue As Variant)
' ByVal gave us a separate, local reference to the object,
' but it's still an object reference, not a value.
varValue.Value = "zzz"
' Because parameter is by ByVal, the next line only affects
' the state of the local varValue.
Set varValue = Me!txtValue1
varValue.Value = "yyy"
End Sub

Nov 13 '05 #4

P: n/a
> Does putting () around an object cause the evaluated value to be
passed?

Wouldn't using ByVal fix the problem, too, assuming you don't want
You do get tricky VB/VBA side effects :~)

For example, this does not just pass a string value:

call sb((codedb.name))

private sub sb(byval s as string)

.... for some reason it actually does retain a
reference to the temporary db object, which you
can see inside sub sb if you iterate through
the databases collection.

This has a quite different effect:
s = codedb.name
call sb(s)

(david)

"David W. Fenton" <dX********@bway.net.invalid> wrote in message
news:Xn**********************************@24.168.1 28.74... Steve Jorgensen <no****@nospam.nospam> wrote in
news:7s********************************@4ax.com:
Again, I recommend solving the problem at both ends, just to cover
all your bases. When you want to pass the value of an object to a
procedure, be explicit about it, and pass something like
Me!txtName.Value. When writing a procedure that takes a variant
and needs to deal only with a value, not an object reference,
convert any object reference you get to a plain value.

Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...


Does putting () around an object cause the evaluated value to be
passed?

Wouldn't using ByVal fix the problem, too, assuming you don't want
to operate on the value itself (which you wouldn't really be able to
do with .Value, anyway)?

--
David W. Fenton http://www.bway.net/~dfenton
dfenton at bway dot net http://www.bway.net/~dfassoc

Nov 13 '05 #5

P: n/a
On Thu, 2 Sep 2004 12:24:17 +1000, "david epsom dot com dot au"
<david@epsomdotcomdotau> wrote:
Does putting () around an object cause the evaluated value to be
passed?

Wouldn't using ByVal fix the problem, too, assuming you don't want


You do get tricky VB/VBA side effects :~)

For example, this does not just pass a string value:

call sb((codedb.name))

private sub sb(byval s as string)

... for some reason it actually does retain a
reference to the temporary db object, which you
can see inside sub sb if you iterate through
the databases collection.

This has a quite different effect:
s = codedb.name
call sb(s)

(david)


To me, that is less of a side effect than what I'm talking about. When a
dynamic object reference is created within a statement, the reference is
always held until the statement completes. This is actually to prevent side
effects such as what would happen if you tried to pass a tabledef to a
procedure using Foo CurrentDb.TableDefs("tblBar"). If the dynamic reference
to the database instance returned by CurrentDb were allowed to go out of scope
immediately, then Foo would not be able to use the TableDef reference that was
passed to it. You can think of the behavior as being similar to a With block.
Nov 13 '05 #6

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:cj********************************@4ax.com...
In another section of my post, I tried (not very well, apparently) to explain why it turns out that it would not, though I've only understood this for a
short time, myself. When objects are involved, ByVal is misnamed, because it doesn't force the object's value to be evaluated, it just makes a new
reference to the object instead of sharing the calling procedure's reference to the object.


What would an object's value be evaluated to? Objects created with
VBA have no way to set a defaut value.

Nov 13 '05 #7

P: n/a
On Thu, 02 Sep 2004 03:22:39 GMT, "rkc" <rk*@yabba.dabba.do.rochester.rr.bomb>
wrote:

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:cj********************************@4ax.com.. .
In another section of my post, I tried (not very well, apparently) to

explain
why it turns out that it would not, though I've only understood this for a
short time, myself. When objects are involved, ByVal is misnamed, because

it
doesn't force the object's value to be evaluated, it just makes a new
reference to the object instead of sharing the calling procedure's

reference
to the object.


What would an object's value be evaluated to? Objects created with
VBA have no way to set a defaut value.


Of course, this whole discussion can only refer to cases where you're passing
around references to objects that do have default value properties. While you
can't (without cheating) create these yourself in VBA, there are many cases
where we use and pass sround existing objects that do have default value
properties, such as fields and controls. It is when we pass these as
arguments to functions that the issues arise.
Nov 13 '05 #8

P: n/a
On Thu, 02 Sep 2004 09:22:50 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
On Wed, 01 Sep 2004 10:26:36 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:
== On Error Resume next, and Err.Number ==

<snip>
Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...


When doing this, use a function, not a sub, and return back the error
number so that the calling function can react to the error.


I'm not sure why that's better.
1. The onus on the error trapping has now simply moved from the calling code
into the called code.
2. Perhaps the procedure to be called is already, logically a function, not a
sub, that returns something else besides an error number as its value. In
other words, we already have a communication channel for error information,
why use up another communication channel that we might want for something
else?
3. What if not every caller expects to repond directly to an error? Perhaps,
the error handling is better done farther up the call stack.

Nov 13 '05 #9

P: n/a
On Thu, 02 Sep 2004 22:51:46 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
On Thu, 02 Sep 2004 20:27:50 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:
On Thu, 02 Sep 2004 09:22:50 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
On Wed, 01 Sep 2004 10:26:36 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:

== On Error Resume next, and Err.Number ==
<snip>
Sub Foo(varValue As Variant)
Dim varUseValue As Variant
varUseValue = varValue
...When doing this, use a function, not a sub, and return back the error
number so that the calling function can react to the error.

I'm not sure why that's better.
1. The onus on the error trapping has now simply moved from the calling code
into the called code.
2. Perhaps the procedure to be called is already, logically a function, not a
sub, that returns something else besides an error number as its value. In
other words, we already have a communication channel for error information,
why use up another communication channel that we might want for something
else?
3. What if not every caller expects to repond directly to an error? Perhaps,
the error handling is better done farther up the call stack.


When you have the error number, the calling code can react in a
"custom" method rather then a general. As you well know, all sorts of
bizarre things can happen to objects as they are passed around and
manipulated by various subs and functions. Especially if the code
called is doing it's own error handling that the calling code will
never know about.


I'm not sure I get what you're getting at. The calling code can respond the
the error in a custom way by trapping the error as well, without needidg the
return value. Admittedly, that takes more code in the calling procedure, but
you're now putting the onus on the called procedure to know that the calling
procedure will want to know the error code, and will want to know it
disticntly for that call and not generically for a series of statements (say,
3 calls within a loop).

Further more, you must either...
A) assume every caller will want error information returned as a parameter,
and always do that, then have to return any other data via reference
parameters which often increases the mumber of lines of code requireds in the
calling procedure
B) modify each procedure when you find out that a calling procedure will want
to handle error information distinctly for that procedure. In this case, you
may break other code that was trapping for errors, and expecting an error
branch if one did occur.

Also, if the called procedure is trapping its own error, how likely is it that
the calling procedure will actually need to know which error it was. Perhaps,
a mere boolean success/failure code would be a more appropriate thing to
return.

I think it's more consistent to try to use the exception handling mechanisms
for error trapping, and use function return values to return processing output
from function procedures.

Here's some thinking out-loud about a sort of compromise between our 2
positions...

Add an optional ByRef Variant parameter to the called procedure that can be
used to retrieve its exception information. Have the called procedure's error
handler re-raise the exception if the variant parameter IsMissing(...), or
pass the error info back to the calling procedure via the parameter if it is
not missing.

Now, the calling procedure can either use error trapping or not as desired,
and it can avoid error trapping without the use of On Error Resume Next simply
by passing an argument to collect the error information. This can be used
even with a function procedure that has reason to return something other than
error information as its return value. One potential source of trouble here
is that the error info parameter must be initialized, and that's easy to
forget. I guess that's an advantage to the return value as opposed to the
ByRef argument.
Nov 13 '05 #10

P: n/a
On Fri, 03 Sep 2004 08:36:21 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
....
I'm not really too sure what you're getting at here either, Steve. If
an error is handled by the sub and cleared, how the heck would the
calling code know there was an error at all? If the calling code
*did* need to know an error occurred, how are you proposing to have
the calling code made aware of that? If I'm reading your post
correctly, then it's your position that there should be no need.
Whatever code needed to handle any and all problem(s) should be in the
Sub, not in the calling code?


Looking back at my post, I'm not surprised, because that's one long and
convoluted discussion. Let's see if I can write more concisely.

First off, no I'm not saying anything categorically about whether error
handling should be in calling code or called code (everything's called code at
some level). I'm just saying that, in general, if a calling procedure needs
to know about an exception that happens in a called procedure, it should use
On Error Goto to handle it.

This is in contradiction to your suggestion that error infomation be passed as
the return value from a function. This is unattractive to me because it seems
to be ignoring a feature that was added to VB specifically to provide a
channel for error information that leaves other channels such as function
return values free to handle other non-exceptional things.

I didn't say this part before, but if the called procedure also needs to do
clean-up in the event of an error, it should do so, then raise the error
again, so the calling code can capture it. I often use a class instance to
store the error info and re-raise it. This class also becomes a convenient
place to put other error handling details, such as logging, message boxes,
etc.

Anyway, in thinking about the difference between our points of view, I had a
thought that one could write a procedure that would sort of work either way.
The procedure would re-raise any errors that occur within it that need to be
handled externally, but only so long as it was not given an optional ByRef
argument that could be used to pass the error information back to the caller.
If it did get that argument, it would pass the error info through that
parameter, and not re-raise the error.

Of course, all of this ignores the cases of exceptions that can be fully
handled within the called procedure, and the calling procedure should not need
to know about. These, of course, should never be returned to the caller, no
matter what scheme is used. I assume we're on the same page on this point.
Nov 13 '05 #11

P: n/a
rkc

"Steve Jorgensen" <no****@nospam.nospam> wrote in message
news:ag********************************@4ax.com...
On Fri, 03 Sep 2004 08:36:21 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
...
I'm not really too sure what you're getting at here either, Steve. If
an error is handled by the sub and cleared, how the heck would the
calling code know there was an error at all? If the calling code
*did* need to know an error occurred, how are you proposing to have
the calling code made aware of that? If I'm reading your post
correctly, then it's your position that there should be no need.
Whatever code needed to handle any and all problem(s) should be in the
Sub, not in the calling code?


Looking back at my post, I'm not surprised, because that's one long and
convoluted discussion. Let's see if I can write more concisely.


The discussion was a bit hard to follow so I may not fully understand what
you
were getting at. What it left me with is a feeling that most of the problems
cited
could be reduced by a move away from convoluted functional based design
toward a more object oriented approach.


Nov 13 '05 #12

P: n/a
> an error is handled by the sub and cleared, how the heck would
calling code know there was an error at all? If the calling
FWIW, I don't clear errors in subroutines. I re-raise
them. My standard error code looks like this:

catch:
gsbErr_Raise mcModuleName, "subName"

At the top level (if it gets that far), a custom message
box displays the error description, suggested response,
and debug stack.
The exception can be suppressed/ignored/corrected at
an stage between the try/catch function and the reporting
function.

(david)

"Chuck Grimsby" <c.*******@worldnet.att.net.invalid> wrote in message
news:2q********************************@4ax.com... On Fri, 03 Sep 2004 00:26:37 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:
On Thu, 02 Sep 2004 22:51:46 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:
On Thu, 02 Sep 2004 20:27:50 GMT, Steve Jorgensen
<no****@nospam.nospam> wrote:

On Thu, 02 Sep 2004 09:22:50 GMT, Chuck Grimsby
<c.*******@worldnet.att.net.invalid> wrote:

>On Wed, 01 Sep 2004 10:26:36 GMT, Steve Jorgensen
><no****@nospam.nospam> wrote:
>
>>== On Error Resume next, and Err.Number ==
><snip>
>>Sub Foo(varValue As Variant)
>> Dim varUseValue As Variant
>> varUseValue = varValue
>> ...

>When doing this, use a function, not a sub, and return back the error
>number so that the calling function can react to the error.

I'm not sure why that's better.
1. The onus on the error trapping has now simply moved from the calling codeinto the called code.
2. Perhaps the procedure to be called is already, logically a function, not asub, that returns something else besides an error number as its value. Inother words, we already have a communication channel for error information,why use up another communication channel that we might want for somethingelse?
3. What if not every caller expects to repond directly to an error? Perhaps,the error handling is better done farther up the call stack.

When you have the error number, the calling code can react in a
"custom" method rather then a general. As you well know, all sorts of
bizarre things can happen to objects as they are passed around and
manipulated by various subs and functions. Especially if the code
called is doing it's own error handling that the calling code will
never know about.


I'm not sure I get what you're getting at. The calling code can respond thethe error in a custom way by trapping the error as well, without needidg thereturn value. Admittedly, that takes more code in the calling procedure, butyou're now putting the onus on the called procedure to know that the callingprocedure will want to know the error code, and will want to know it
disticntly for that call and not generically for a series of statements (say,3 calls within a loop).

Further more, you must either...
A) assume every caller will want error information returned as a parameter,and always do that, then have to return any other data via reference
parameters which often increases the mumber of lines of code requireds in thecalling procedure
B) modify each procedure when you find out that a calling procedure will wantto handle error information distinctly for that procedure. In this case, youmay break other code that was trapping for errors, and expecting an error
branch if one did occur.

Also, if the called procedure is trapping its own error, how likely is it thatthe calling procedure will actually need to know which error it was. Perhaps,a mere boolean success/failure code would be a more appropriate thing to
return.

I think it's more consistent to try to use the exception handling mechanismsfor error trapping, and use function return values to return processing outputfrom function procedures.

Here's some thinking out-loud about a sort of compromise between our 2
positions...

Add an optional ByRef Variant parameter to the called procedure that can beused to retrieve its exception information. Have the called procedure's errorhandler re-raise the exception if the variant parameter IsMissing(...), orpass the error info back to the calling procedure via the parameter if it isnot missing.

Now, the calling procedure can either use error trapping or not as desired,and it can avoid error trapping without the use of On Error Resume Next simplyby passing an argument to collect the error information. This can be usedeven with a function procedure that has reason to return something other thanerror information as its return value. One potential source of trouble hereis that the error info parameter must be initialized, and that's easy to
forget. I guess that's an advantage to the return value as opposed to theByRef argument.


I'm not really too sure what you're getting at here either, Steve. If
an error is handled by the sub and cleared, how the heck would the
calling code know there was an error at all? If the calling code
*did* need to know an error occurred, how are you proposing to have
the calling code made aware of that? If I'm reading your post
correctly, then it's your position that there should be no need.
Whatever code needed to handle any and all problem(s) should be in the
Sub, not in the calling code?
--
A Programmer And His Mind Are Soon Parted

Nov 13 '05 #13

P: n/a
On Mon, 6 Sep 2004 09:54:44 +1000, "david epsom dot com dot au"
<david@epsomdotcomdotau> wrote:
an error is handled by the sub and cleared, how the heck would
calling code know there was an error at all? If the calling


FWIW, I don't clear errors in subroutines. I re-raise
them. My standard error code looks like this:

catch:
gsbErr_Raise mcModuleName, "subName"

At the top level (if it gets that far), a custom message
box displays the error description, suggested response,
and debug stack.
The exception can be suppressed/ignored/corrected at
an stage between the try/catch function and the reporting
function.

(david)


Well, the reason I came across this issue in the first place is that,
sometimes an error is completely handled within the called function, so
there's no reason to let the calling function know about it. The problem is
that, if the called function tries an operatino that might raise an error
using On Error Resume Next, then checks Err.Number, if it doesn't also clear
the error, and if the calling procedure tries the same thing when calling the
called procedure, it may see that same error information still in the Err
object, and think this was an unhandled or re-raised error from the called
procedure.

That's why I say to block this problem at both ends, by clearing any error
information after an On Error Resume Next block in the called procedure
(assuming the error is handled locally and there is no reason to re-raise it),
and by having the calling procedure never try to identify errors from a called
procedure in the same project with On Error Resume Next, only with On Error
Goto <label>.
Nov 13 '05 #14

This discussion thread is closed

Replies have been disabled for this discussion.