Group:  Microsoft Access ยป microsoft.public.access.modulescoding
Thread: ByVal and ByRef

DotNetBag
.NET Development Newsgroups

HTVi
TV Discussion Newsgroups

Our Hot Pick: Rising Antivirus 2006 - Certified by TUV & Checkmark! Get 10% discount by entering this coupon code: ONDISCOUNT10
Rising Antivirus 2006

ByVal and ByRef
MarkSiegel 18.09.2006 00:17:01
Can anyone explain when to use these two terms in English?
I like to think I am a pretty smart guy but I just dont get it when it comes
to these two................
Thanks!Mark
Re: ByVal and ByRef
"David Cox" <davidfcox[ at ]ntlworld.com> 18.09.2006 00:38:19
if you pass a parameter, say X by ref(erence) and you can change the value
of X within the subroutine or function whatever was passed as X outside the
sub or function it will change too.

If you pass X ByVal (By Value) then it is a copy of X that is passed If you
change X inside the function then what was passed as X outside the sub or
function is unchanged.

myval = 6
mysub myval
myothersub myval
......

sub mysub (X as integer) 'ByRef as default
.....
X = 99 'changes myval to 99
......
end sub

sub myothersub (ByVal X as Integer)
....
X = 0 ' myval stays as it was on entry
.....
end sub

HTH


"MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:5AD4AFF4-0A9C-42CC-AE3E-A2D081198620[ at ]microsoft.com...
[Quoted Text]
> Can anyone explain when to use these two terms in English?
> I like to think I am a pretty smart guy but I just dont get it when it
> comes
> to these two................
> Thanks!Mark


Re: ByVal and ByRef
MarkSiegel 18.09.2006 01:07:01
I am starting to understand. But I dont see the practical application.
Do you have an example??Thanks Mark

"David Cox" wrote:

[Quoted Text]
> if you pass a parameter, say X by ref(erence) and you can change the value
> of X within the subroutine or function whatever was passed as X outside the
> sub or function it will change too.
>
> If you pass X ByVal (By Value) then it is a copy of X that is passed If you
> change X inside the function then what was passed as X outside the sub or
> function is unchanged.
>
> myval = 6
> mysub myval
> myothersub myval
> ......
>
> sub mysub (X as integer) 'ByRef as default
> .....
> X = 99 'changes myval to 99
> ......
> end sub
>
> sub myothersub (ByVal X as Integer)
> ....
> X = 0 ' myval stays as it was on entry
> .....
> end sub
>
> HTH
>
>
> "MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
> news:5AD4AFF4-0A9C-42CC-AE3E-A2D081198620[ at ]microsoft.com...
> > Can anyone explain when to use these two terms in English?
> > I like to think I am a pretty smart guy but I just dont get it when it
> > comes
> > to these two................
> > Thanks!Mark
>
>
>
Re: ByVal and ByRef
"David Cox" <davidfcox[ at ]ntlworld.com> 18.09.2006 02:57:03
http://support.microsoft.com/kb/118643/EN-US/


"MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:27B6C041-BF31-41FB-8706-FAD1D736E046[ at ]microsoft.com...
[Quoted Text]
>I am starting to understand. But I dont see the practical application.
> Do you have an example??Thanks Mark
>
> "David Cox" wrote:
>
>> if you pass a parameter, say X by ref(erence) and you can change the
>> value
>> of X within the subroutine or function whatever was passed as X outside
>> the
>> sub or function it will change too.
>>
>> If you pass X ByVal (By Value) then it is a copy of X that is passed If
>> you
>> change X inside the function then what was passed as X outside the sub or
>> function is unchanged.
>>
>> myval = 6
>> mysub myval
>> myothersub myval
>> ......
>>
>> sub mysub (X as integer) 'ByRef as default
>> .....
>> X = 99 'changes myval to 99
>> ......
>> end sub
>>
>> sub myothersub (ByVal X as Integer)
>> ....
>> X = 0 ' myval stays as it was on entry
>> .....
>> end sub
>>
>> HTH
>>
>>
>> "MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
>> news:5AD4AFF4-0A9C-42CC-AE3E-A2D081198620[ at ]microsoft.com...
>> > Can anyone explain when to use these two terms in English?
>> > I like to think I am a pretty smart guy but I just dont get it when it
>> > comes
>> > to these two................
>> > Thanks!Mark
>>
>>
>>


Re: ByVal and ByRef
Marshall Barton <marshbarton[ at ]wowway.com> 18.09.2006 14:00:42
Other considerations are that passing arguments by ref is
generally more efficient for several reasons. The potential
for modification of the calling procedure's variable is
often a negative side effect. There are some situations
where modifying the caller's variables is necessary so By
Ref is essential to the purpose of the procedure.

Using By Val is can be less efficient, but it is safer.
--
Marsh
MVP [MS Access]


MarkSiegel wrote:
[Quoted Text]
>I am starting to understand. But I dont see the practical application.
>Do you have an example??Thanks Mark
>
>"David Cox" wrote:
>> if you pass a parameter, say X by ref(erence) and you can change the value
>> of X within the subroutine or function whatever was passed as X outside the
>> sub or function it will change too.
>>
>> If you pass X ByVal (By Value) then it is a copy of X that is passed If you
>> change X inside the function then what was passed as X outside the sub or
>> function is unchanged.
>>
>> myval = 6
>> mysub myval
>> myothersub myval
>> ......
>>
>> sub mysub (X as integer) 'ByRef as default
>> .....
>> X = 99 'changes myval to 99
>> ......
>> end sub
>>
>> sub myothersub (ByVal X as Integer)
>> ....
>> X = 0 ' myval stays as it was on entry
>> .....
>> end sub
>>
>>
>> "MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote
>> > Can anyone explain when to use these two terms in English?
>> > I like to think I am a pretty smart guy but I just dont get it when it
>> > comes to these two................

Re: ByVal and ByRef
"Albert D. Kallal" <PleaseNOOOsPAMmkallal[ at ]msn.com> 18.09.2006 15:26:47
MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:27B6C041-BF31-41FB-8706-FAD1D736E046[ at ]microsoft.com...
[Quoted Text]
>I am starting to understand. But I dont see the practical application.
> Do you have an example??Thanks Mark

There are several ramifications of using byVal, or ByRef.

As mentioned, the MOST important aspect of this feature is that ByVal means
that the routine you call CAN NOT MODIFY the value.

Eg:

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

The above call to a subroutine passes the value of strText. Note that the
DEFAULT in ms-access is byRef.

What the above means is that the MyCoolsub CAN CHANGE THE VALUE of strText

Lets assume the mycoolsub is as follows

Sub MyCoolSub(strT as string)

strT = "def"

end sub


So, if we go

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

msgbox "the value of strText is now = " & strText

the above routine would display msgbox with

the value of strtext is now = def

You can well see that our sub routine MODIFIED the value we passed to that
routine.

However, if we declare that sub-routine as follows:

Sub MyCoolSub(byVal strT as string)

strT = "def"

end sub

now, if we run our code like

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

msgbox "the value of strText is now = " & strText

the above routine would display msgbox with

the value of strtext is now = abc

What this means is that the parameter we are sending to the subroutine CAN
NOT be changed. This means that as a developer, if I see a sub routine
defined like:

Sub TaxCalc (ByVal taxRate as currency, ByValue EmployeeID as long, ByRef
TaxResults as currency)


Note that looking at the above, as a developer I can INSTANTLY see that the
first two values of the sub are only values that we PASS TO THE sub, and
they CAN NOT BE CHANGED (and, if they are changed..the changes will be ONLY
LIMITED to the TaxCalc routine..and the results WILL NEVER be returned, or
changed for the first two parameters of the sub). This means we can use this
fact to write more reliable code, since even if you new junior programmer
modifies the TaxCalc routine,a nd CHANGES the value of TaxRate, or
EmployeeID in the code, the calling routine will NOT have its values
changed.

Ok, pop question then?

Why is the default byRef when ByVal is MUCH safer?

Well, the reason is mostly as to how computers work. You see, when you use
ByVal, the computer actually makes a copy of the variables, and uses them
for that subroutine you just called (since a COPY is made, then you are free
to change the values..but the changes are ONLY local to that subroutine).
When you exit the sub-rotting, those copied values are just tossed out.

When you use ByRef, in fact what happens is that the variables is NOT
actually passed, but the computer actually passes a REFERENCE to the
EXISTING variable in memory. This can result in a SIGNIFICANT performance
advantage, since if your string is 30,000 characters long. that is a LOT of
data to copy. further, the same thing applies when you pass an array of
data. That array might have 45000 elements, and if you pass byVal, then the
computer needs to make a COPY of the data (since, as mentioned, if any code
in the subroutine changes the values, they are NOT reflected back to the
calling code).

So, the reason why ms-access defaults to a MORE DANGEROUS setting of byRef
is for performance reasons.

A REALLY good developer will actually ALWAYS include the byval, or byref
defining in the subroutine. This does two important things

a) makes code more reliable, since you can't actually change a value
that the developer did not expect to be changed
b) anyone reading the subroutine declare can INSTANTLY understand
what vales/parameters passed to the routine can be changed (or are EXPECTED
to be changed by the developer). So, it becomes a documentation issue, and
communication issue to those reading your code.


So, byRef actually means that the variables is not passed to the subroutine,
but the actually references. And, thus, if you change this value in the
sub-routine, it will be returned back.

As a general rule, ByVal means that you can't accidentally damage, or change
the value of a variable. However, you pay for this safety in terms of a
performance hit, as a "copy" of the data is made when you use byVal. Today,
since the computer is so fast, the documentation, and safety issues outweigh
that of performance in most cases. However, for looping code that calls the
same subroutine over an over, then substantial performance gains can be had
by using the default "byRef" since NO copy of the variable(S) are made.


--
Albert D. Kallal (Access MVP)
Edmonton, Alberta Canada
pleaseNOOSpamKallal[ at ]msn.com



Re: ByVal and ByRef
"Albert D. Kallal" <PleaseNOOOsPAMmkallal[ at ]msn.com> 18.09.2006 15:27:10
MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:27B6C041-BF31-41FB-8706-FAD1D736E046[ at ]microsoft.com...
[Quoted Text]
>I am starting to understand. But I dont see the practical application.
> Do you have an example??Thanks Mark

There are several ramifications of using byVal, or ByRef.

As mentioned, the MOST important aspect of this feature is that ByVal means
that the routine you call CAN NOT MODIFY the value.

Eg:

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

The above call to a subroutine passes the value of strText. Note that the
DEFAULT in ms-access is byRef.

What the above means is that the MyCoolsub CAN CHANGE THE VALUE of strText

Lets assume the mycoolsub is as follows

Sub MyCoolSub(strT as string)

strT = "def"

end sub


So, if we go

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

msgbox "the value of strText is now = " & strText

the above routine would display msgbox with

the value of strtext is now = def

You can well see that our sub routine MODIFIED the value we passed to that
routine.

However, if we declare that sub-routine as follows:

Sub MyCoolSub(byVal strT as string)

strT = "def"

end sub

now, if we run our code like

dim strtext as string

strText = "abc"

Call MyCoolSub(strText)

msgbox "the value of strText is now = " & strText

the above routine would display msgbox with

the value of strtext is now = abc

What this means is that the parameter we are sending to the subroutine CAN
NOT be changed. This means that as a developer, if I see a sub routine
defined like:

Sub TaxCalc (ByVal taxRate as currency, ByValue EmployeeID as long, ByRef
TaxResults as currency)


Note that looking at the above, as a developer I can INSTANTLY see that the
first two values of the sub are only values that we PASS TO THE sub, and
they CAN NOT BE CHANGED (and, if they are changed..the changes will be ONLY
LIMITED to the TaxCalc routine..and the results WILL NEVER be returned, or
changed for the first two parameters of the sub). This means we can use this
fact to write more reliable code, since even if you new junior programmer
modifies the TaxCalc routine,a nd CHANGES the value of TaxRate, or
EmployeeID in the code, the calling routine will NOT have its values
changed.

Ok, pop question then?

Why is the default byRef when ByVal is MUCH safer?

Well, the reason is mostly as to how computers work. You see, when you use
ByVal, the computer actually makes a copy of the variables, and uses them
for that subroutine you just called (since a COPY is made, then you are free
to change the values..but the changes are ONLY local to that subroutine).
When you exit the sub-rotting, those copied values are just tossed out.

When you use ByRef, in fact what happens is that the variables is NOT
actually passed, but the computer actually passes a REFERENCE to the
EXISTING variable in memory. This can result in a SIGNIFICANT performance
advantage, since if your string is 30,000 characters long. that is a LOT of
data to copy. further, the same thing applies when you pass an array of
data. That array might have 45000 elements, and if you pass byVal, then the
computer needs to make a COPY of the data (since, as mentioned, if any code
in the subroutine changes the values, they are NOT reflected back to the
calling code).

So, the reason why ms-access defaults to a MORE DANGEROUS setting of byRef
is for performance reasons.

A REALLY good developer will actually ALWAYS include the byval, or byref
defining in the subroutine. This does two important things

a) makes code more reliable, since you can't actually change a value
that the developer did not expect to be changed
b) anyone reading the subroutine declare can INSTANTLY understand
what vales/parameters passed to the routine can be changed (or are EXPECTED
to be changed by the developer). So, it becomes a documentation issue, and
communication issue to those reading your code.


So, byRef actually means that the variables is not passed to the subroutine,
but the actually references. And, thus, if you change this value in the
sub-routine, it will be returned back.

As a general rule, ByVal means that you can't accidentally damage, or change
the value of a variable. However, you pay for this safety in terms of a
performance hit, as a "copy" of the data is made when you use byVal. Today,
since the computer is so fast, the documentation, and safety issues outweigh
that of performance in most cases. However, for looping code that calls the
same subroutine over an over, then substantial performance gains can be had
by using the default "byRef" since NO copy of the variable(S) are made.


--
Albert D. Kallal (Access MVP)
Edmonton, Alberta Canada
pleaseNOOSpamKallal[ at ]msn.com




Re: ByVal and ByRef
"Geoff" <geoff[ at ]nospam.com> 18.09.2006 20:22:55
Say Value1 is stored at MemoryAddress1.

Passing the value ByRef means you pass MemoryAddress1 (ie a pointer to
Value1), so Value1 at MemoryAddress1 can be changed by the called routine.

Passing the value ByVal means Value1 is copied to MemoryAddress2 and the
called routine works on Value1 at MemoryAddress2. Therefore Value1 at
MemoryAddress1 will not be changed by the called routine.

G.

"MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:5AD4AFF4-0A9C-42CC-AE3E-A2D081198620[ at ]microsoft.com...
[Quoted Text]
> Can anyone explain when to use these two terms in English?
> I like to think I am a pretty smart guy but I just dont get it when it
> comes
> to these two................
> Thanks!Mark


Two Practical Examples
"Geoff" <geoff[ at ]nospam.com> 19.09.2006 09:15:21
Here are two practical (if trivial) examples to illustrate what happens.

Which method you use, often depends on what you want to do and your
programming style. You may like to copy and paste the examples below into
VBA as a demonstration.

G.


EXAMPLE 1 (ByVal)

Private Sub PassByVal()

' Call a function to calculate the square root
' of a number and store the result in a new variable.

Dim dblN As Double
Dim dblSR As Double

dblN = 25

' Call the GetSquareRoot1 function:
dblSR = GetSquareRoot1(dblN)

' Display both original and square-root numbers:
MsgBox "Original Number = " & CStr(dblN) _
& vbNewLine _
& "Square Root = " & dblSR _
& vbNewLine & vbNewLine _
& "Notice dblN has not changed " _
& "after the call to the function."

End Sub

Private Function GetSquareRoot1(ByVal dblN As Double) As Double

' This function returns the square root.
'
' ByVal (above) creates a new copy of dblN inside this
' function, which is only seen by this function.
' Therefore, dblN is not updated in the calling routine,
' even though dblN is updated in this function.

' Calculate the square root and store result in the
' local copy of dblN:
dblN = Sqr(dblN)

' Return square root:
GetSquareRoot1 = dblN

End Function


EXAMPLE 2 (ByRef):

Private Sub PassByRef()

' Call a subprocedure to calculate the square root
' of a number and store the square root (the result)
' in the variable declared in this routine.

Dim dblN As Double

dblN = 25

' Call the GetSquareRoot1 subprocedure:
Call GetSquareRoot2(dblN)

' Display the updated dblN value:
MsgBox "Square Root = " & dblN _
& vbNewLine & vbNewLine _
& "Notice dblN has been changed " _
& "after the call to the subroutine."

' One quirk to be aware of:
'
' You can call GetSquareRoot2 in one of two ways:
'
' 1. With "Call" and brackets round argument (which is the
' preferred method), eg:
'
' Call GetSquareRoot2(dblN)

' Or:
'
' 2. Without "Call" and no brackets round argument, eg
'
' GetSquareRoot2 dblN
'
' If you put dblN in brackets without the "Call" statement,
' you will override "ByRef" and pass "ByVal". Therefore,
' don't call the subroutine as follows (not unless you want
' to force "ByVal"):
'
' GetSquareRoot2 (dblN)

End Sub

Private Sub GetSquareRoot2(ByRef dblN As Double)

' ByRef (above) points dblN to the dblN declared in
' calling routine. Therefore, this subroutine updates
' dblN in the calling routine to the square root value.

' Calculate the square root:
dblN = Sqr(dblN)

End Sub




Re: ByVal and ByRef
<david[ at ]epsomdotcomdotau> 19.09.2006 11:17:11
Just to make it more confusing,

The main reason why you would want to pass ByRef, is to pass
a reference to something like a Form, so you could have a subroutine
that did things to Forms.

But Forms are references anyway, so even if you use ByVal, you
get the Value of the Reference - and with that Reference you can
make any change you want, just as if you had passed a reference
to the reference.

ByVal is a good way to indicate that you don't want something to change,
but if you pass complex objects like forms, recordsets, etc, you still have
to be careful - they don't work the way you might expect.

(david)


"MarkSiegel" <MarkSiegel[ at ]discussions.microsoft.com> wrote in message
news:5AD4AFF4-0A9C-42CC-AE3E-A2D081198620[ at ]microsoft.com...
[Quoted Text]
> Can anyone explain when to use these two terms in English?
> I like to think I am a pretty smart guy but I just dont get it when it
comes
> to these two................
> Thanks!Mark


Practical Example (Less Trivial)
"Geoff" <geoff[ at ]nospam.com> 20.09.2006 02:22:34
Here is a practical example of when ByRef can be useful.

A function can only return one value to a calling routine. But say you want
a function to return multiple values.

To achieve this, pass multiple arguments ByRef to the function. The function
can then use these arguments to return values to the calling routine.

In outline:

1. The calling routine declares variables.
2. Some variables are given values and some are left empty.
3. The calling routine passes the variables ByRef to the function.
4. The function uses the values passed in to calculate new values.
5. The function stores the new values in the empty variables.
6. The function finishes and returns a value to the calling routine.
7. This return value indicates success or failure.
8. The calling routine still has access to the new values because the
variables were passed ByRef.

The code below illustrates the process. For convenience, the function's
multiple arguments are stored in a single user-defined type "CalcValues".
This structure includes the one value that is passed into the function
(InputNumber) and the three other values the function passes back to the
calling routine (Square, Square Root and Log).

If the function succeeds, the function will return zero. If the function
fails, the function will return an error constant. The calling routine
examines the return value and stops if an error occurs.

Copy the code below to a VBA module and run "TestCalcValuesFunction".

G.


CODE BEGINS:

' The user-defined data type CalcValues
' (below) is a structure that will hold the
' following elements:
'
' 1. InputNumber - the number that will be passed
' to the CalcValues function.
'
' 2. The values calculated by the same function
' will be placed in the other elements of
' the structure.

Private Type CalcValues
InputNumber As Variant
Square As Double
SquareRoot As Double
Log As Double
End Type


' Error messages for CalcValues function:

Private Const CalcErrNum1 As Integer = 1
Private Const CalcErrMsg1 As String = _
"The CalcValues function received non-numeric input."

Private Const CalcErrNum2 As Integer = 2
Private Const CalcErrMsg2 As String = _
"The CalcValues function cannot calculate the square for "

Private Const CalcErrNum3 As Integer = 3
Private Const CalcErrMsg3 As String = _
"The CalcValues function cannot calculate the square root for "

Private Const CalcErrNum4 As Integer = 4
Private Const CalcErrMsg4 As String = _
"The CalcValues function cannot calculate the logarithm for "

Private Const CalcErrNum5 As Integer = 5
Private Const CalcErrMsg5 As String = _
"The CalcValues function returned an unknown error."


Private Sub TestCalcValuesFunction()

' Declare some variables:
Dim I As Integer
Dim intRetVal As Integer
Dim strErrMsg As String
Dim CV As CalcValues

' Print heading in Immediate window:
Debug.Print "NUMBER", "SQUARE", "SQUARE ROOT", , "LOG"

' Loop to call function multiple times:
For I = 1 To 100

' Put next number in CV:
CV.InputNumber = I

' Call the CalcValues function and
' capture its return value:
intRetVal = CalcValues(CV)

' See if function returned an error:
If intRetVal <> 0 Then GoTo Err_CalcValues

' As error not encountered, send calculations
' to Immediate window:
Debug.Print CV.InputNumber, CV.Square, _
CV.SquareRoot; Tab(57); CV.Log

Next

MsgBox "Open Immediate window to see results."

Bye:

Exit Sub

Err_CalcValues:

' The CalcValues function returned an error.
' Display appropriate error message.
Select Case intRetVal
Case CalcErrNum1
strErrMsg = CalcErrMsg1
Case CalcErrNum2
strErrMsg = CalcErrMsg2 & CStr(I)
Case CalcErrNum3
strErrMsg = CalcErrMsg3 & CStr(I)
Case CalcErrNum4
strErrMsg = CalcErrMsg4 & CStr(I)
Case Else
' Shouldn't happen:
strErrMsg = CalcErrMsg5
End Select
MsgBox strErrMsg, vbExclamation + vbOKOnly, "Error"

GoTo Bye

End Sub

Private Function CalcValues(ByRef CV As CalcValues) As Integer

' This function will calculate the square, square root,
' and log of a number and return these three calculations
' to the calling routine.
'
' IN:
'
' CV, declared as user-defined type "CalcValues".
' CV.InputNumber needs to be given a number by the
' calling routine.
'
' OUT:
'
' On success, the square, square root and log of
' CV.InputNumber will be in CV.Square, CV.SquareRoot,
' and CV.Log respectively.
'
' RETURNS:
'
' This function returns an integer as follows:
' Zero on success;
' Non-zero on failure (see error constants).


' Declarations:
Dim intRetVal As Integer
Dim dblSq As Double
Dim dblSqRt As Double
Dim dblLog As Double

' Catch errors (if any) as they happen
' and return appropriate error constant:
On Error Resume Next

' Clear CV:
CV.Square = 0
CV.SquareRoot = 0
CV.Log = 0

' Test incoming value:
If Not IsNumeric(CV.InputNumber) Then
' Return error and exit:
intRetVal = CalcErrNum1
GoTo Bye
End If

' Calculate the square:
dblSq = CV.InputNumber ^ 2
If Err.Number <> 0 Then
' Return error and exit:
intRetVal = CalcErrNum2
GoTo Bye
Else
' Put square calculation in CV.Square:
CV.Square = dblSq
End If

' Calculate the square root:
dblSqRt = Sqr(CV.InputNumber)
If Err.Number <> 0 Then
' Return error and exit:
intRetVal = CalcErrNum3
GoTo Bye
Else
' Put square root calculation in CV.SquareRoot:
CV.SquareRoot = dblSqRt
End If

' Calculate the log:
dblLog = Log(CV.InputNumber)
If Err.Number <> 0 Then
' Return error and exit:
intRetVal = CalcErrNum4
GoTo Bye
Else
' Put log calculation in CV.Log:
CV.Log = dblLog
End If

' The function has succeeded.
' Unnecessary but for clarity:
intRetVal = 0

Bye:

' Set return value:
CalcValues = intRetVal

End Function

CODE ENDS



Re: Practical Example (Less Trivial)
<david[ at ]epsomdotcomdotau> 20.09.2006 21:30:42
This is an example for a language that does not support
exceptions. You see this style of code when doing calls
to the Windows API, because the Windows API does
not export exceptions. Also, old style C did not have a
run-time supervisor, so old style C was written like this.


When calling Com objects, or when writing your own
code, you would expect the function to return the structure,
and exceptions like "non-numeric input" to be returned
as exceptions.

(david)

"Geoff" <geoff[ at ]nospam.com> wrote in message
news:Ok648tF3GHA.4588[ at ]TK2MSFTNGP04.phx.gbl...
[Quoted Text]
> Here is a practical example of when ByRef can be useful.
>
> A function can only return one value to a calling routine. But say you
want
> a function to return multiple values.
>
> To achieve this, pass multiple arguments ByRef to the function. The
function
> can then use these arguments to return values to the calling routine.
>
> In outline:
>
> 1. The calling routine declares variables.
> 2. Some variables are given values and some are left empty.
> 3. The calling routine passes the variables ByRef to the function.
> 4. The function uses the values passed in to calculate new values.
> 5. The function stores the new values in the empty variables.
> 6. The function finishes and returns a value to the calling routine.
> 7. This return value indicates success or failure.
> 8. The calling routine still has access to the new values because the
> variables were passed ByRef.
>
> The code below illustrates the process. For convenience, the function's
> multiple arguments are stored in a single user-defined type "CalcValues".
> This structure includes the one value that is passed into the function
> (InputNumber) and the three other values the function passes back to the
> calling routine (Square, Square Root and Log).
>
> If the function succeeds, the function will return zero. If the function
> fails, the function will return an error constant. The calling routine
> examines the return value and stops if an error occurs.
>
> Copy the code below to a VBA module and run "TestCalcValuesFunction".
>
> G.
>
>
> CODE BEGINS:
>
> ' The user-defined data type CalcValues
> ' (below) is a structure that will hold the
> ' following elements:
> '
> ' 1. InputNumber - the number that will be passed
> ' to the CalcValues function.
> '
> ' 2. The values calculated by the same function
> ' will be placed in the other elements of
> ' the structure.
>
> Private Type CalcValues
> InputNumber As Variant
> Square As Double
> SquareRoot As Double
> Log As Double
> End Type
>
>
> ' Error messages for CalcValues function:
>
> Private Const CalcErrNum1 As Integer = 1
> Private Const CalcErrMsg1 As String = _
> "The CalcValues function received non-numeric input."
>
> Private Const CalcErrNum2 As Integer = 2
> Private Const CalcErrMsg2 As String = _
> "The CalcValues function cannot calculate the square for "
>
> Private Const CalcErrNum3 As Integer = 3
> Private Const CalcErrMsg3 As String = _
> "The CalcValues function cannot calculate the square root for "
>
> Private Const CalcErrNum4 As Integer = 4
> Private Const CalcErrMsg4 As String = _
> "The CalcValues function cannot calculate the logarithm for "
>
> Private Const CalcErrNum5 As Integer = 5
> Private Const CalcErrMsg5 As String = _
> "The CalcValues function returned an unknown error."
>
>
> Private Sub TestCalcValuesFunction()
>
> ' Declare some variables:
> Dim I As Integer
> Dim intRetVal As Integer
> Dim strErrMsg As String
> Dim CV As CalcValues
>
> ' Print heading in Immediate window:
> Debug.Print "NUMBER", "SQUARE", "SQUARE ROOT", , "LOG"
>
> ' Loop to call function multiple times:
> For I = 1 To 100
>
> ' Put next number in CV:
> CV.InputNumber = I
>
> ' Call the CalcValues function and
> ' capture its return value:
> intRetVal = CalcValues(CV)
>
> ' See if function returned an error:
> If intRetVal <> 0 Then GoTo Err_CalcValues
>
> ' As error not encountered, send calculations
> ' to Immediate window:
> Debug.Print CV.InputNumber, CV.Square, _
> CV.SquareRoot; Tab(57); CV.Log
>
> Next
>
> MsgBox "Open Immediate window to see results."
>
> Bye:
>
> Exit Sub
>
> Err_CalcValues:
>
> ' The CalcValues function returned an error.
> ' Display appropriate error message.
> Select Case intRetVal
> Case CalcErrNum1
> strErrMsg = CalcErrMsg1
> Case CalcErrNum2
> strErrMsg = CalcErrMsg2 & CStr(I)
> Case CalcErrNum3
> strErrMsg = CalcErrMsg3 & CStr(I)
> Case CalcErrNum4
> strErrMsg = CalcErrMsg4 & CStr(I)
> Case Else
> ' Shouldn't happen:
> strErrMsg = CalcErrMsg5
> End Select
> MsgBox strErrMsg, vbExclamation + vbOKOnly, "Error"
>
> GoTo Bye
>
> End Sub
>
> Private Function CalcValues(ByRef CV As CalcValues) As Integer
>
> ' This function will calculate the square, square root,
> ' and log of a number and return these three calculations
> ' to the calling routine.
> '
> ' IN:
> '
> ' CV, declared as user-defined type "CalcValues".
> ' CV.InputNumber needs to be given a number by the
> ' calling routine.
> '
> ' OUT:
> '
> ' On success, the square, square root and log of
> ' CV.InputNumber will be in CV.Square, CV.SquareRoot,
> ' and CV.Log respectively.
> '
> ' RETURNS:
> '
> ' This function returns an integer as follows:
> ' Zero on success;
> ' Non-zero on failure (see error constants).
>
>
> ' Declarations:
> Dim intRetVal As Integer
> Dim dblSq As Double
> Dim dblSqRt As Double
> Dim dblLog As Double
>
> ' Catch errors (if any) as they happen
> ' and return appropriate error constant:
> On Error Resume Next
>
> ' Clear CV:
> CV.Square = 0
> CV.SquareRoot = 0
> CV.Log = 0
>
> ' Test incoming value:
> If Not IsNumeric(CV.InputNumber) Then
> ' Return error and exit:
> intRetVal = CalcErrNum1
> GoTo Bye
> End If
>
> ' Calculate the square:
> dblSq = CV.InputNumber ^ 2
> If Err.Number <> 0 Then
> ' Return error and exit:
> intRetVal = CalcErrNum2
> GoTo Bye
> Else
> ' Put square calculation in CV.Square:
> CV.Square = dblSq
> End If
>
> ' Calculate the square root:
> dblSqRt = Sqr(CV.InputNumber)
> If Err.Number <> 0 Then
> ' Return error and exit:
> intRetVal = CalcErrNum3
> GoTo Bye
> Else
> ' Put square root calculation in CV.SquareRoot:
> CV.SquareRoot = dblSqRt
> End If
>
> ' Calculate the log:
> dblLog = Log(CV.InputNumber)
> If Err.Number <> 0 Then
> ' Return error and exit:
> intRetVal = CalcErrNum4
> GoTo Bye
> Else
> ' Put log calculation in CV.Log:
> CV.Log = dblLog
> End If
>
> ' The function has succeeded.
> ' Unnecessary but for clarity:
> intRetVal = 0
>
> Bye:
>
> ' Set return value:
> CalcValues = intRetVal
>
> End Function
>
> CODE ENDS
>
>
>


Re: Practical Example (Less Trivial)
"Geoff" <geoff[ at ]nospam.com> 21.09.2006 10:06:00
David,

Many thanks. I'm learning too!

[Quoted Text]
> You see this style of code when doing calls
> to the Windows API...

Yes, indeed. I think there may also be a parallel with old DOS programs that
used to return errorlevels.

> When calling Com objects, or when writing your own
> code, you would expect the function to return the
> structure, and exceptions...

How should a VB function return exceptions? Should it:

(1) place special values in the structure - in which case should the
structure contain an argument for reporting back exceptions; or
(2) generate a runtime error; or
(3) use CVErr to return a user-defined error.

I imagine you probably don't mean (2) or (3) but just asking...

Geoff


<david[ at ]epsomdotcomdotau> wrote in message
news:eBxCouP3GHA.2196[ at ]TK2MSFTNGP06.phx.gbl...
> This is an example for a language that does not support
> exceptions. You see this style of code when doing calls
> to the Windows API, because the Windows API does
> not export exceptions. Also, old style C did not have a
> run-time supervisor, so old style C was written like this.
>
>
> When calling Com objects, or when writing your own
> code, you would expect the function to return the structure,
> and exceptions like "non-numeric input" to be returned
> as exceptions.
>
> (david)
>


Re: Practical Example (Less Trivial)
"Geoff" <geoff[ at ]nospam.com> 21.09.2006 10:26:24
[Quoted Text]
> You see this style of code when doing calls
> to the Windows API...

Yes, I know. I think there is also be a parallel with old DOS programs that
used to return errorlevels.

> When calling Com objects, or when writing your own
> code, you would expect the function to return the
> structure, and exceptions like "non-numeric input" to be
> returned as exceptions.

How would you expect a VB function return exceptions?

G


<david[ at ]epsomdotcomdotau> wrote in message
news:eBxCouP3GHA.2196[ at ]TK2MSFTNGP06.phx.gbl...
> This is an example for a language that does not support
> exceptions. You see this style of code when doing calls
> to the Windows API, because the Windows API does
> not export exceptions. Also, old style C did not have a
> run-time supervisor, so old style C was written like this.
>
>
> When calling Com objects, or when writing your own
> code, you would expect the function to return the structure,
> and exceptions like "non-numeric input" to be returned
> as exceptions.
>
> (david)
>



Re: Practical Example (Less Trivial)
"Geoff" <geoff[ at ]nospam.com> 21.09.2006 10:36:18
I didn't mean to post this one!

G


Re: Practical Example (Less Trivial)
<david[ at ]epsomdotcomdotau> 24.09.2006 01:00:50
[Quoted Text]
> How would you expect a VB function return exceptions?

If you were writing a general SquareRoot function for other
people to use, you might strip out all of your custom exception
handling code, and just let if fail on strings and negative numbers.
VB would generate an exception, which would be passed by
VB to the calling code. The VB exceptions would be standard
exceptions, and your general users would recognise them as
standard exceptions.

That is a very good way to handle exceptions: in fact, that
is the default way to handle exceptions in VBA code, because
it is a very good way to handle exceptions.

In my own code, I have extra handling, because we have ongoing
development that has been in process for more than 10 years.
We capture information about exceptions, so that it can be used
in test and development. In this respect, VB is not a great test and
development environment for complex projects, so we have extra
code for the framework, but the end result is the same as the
VB default: if there is an exception in SquareRoot, you see it as
an exception in the calling code.

In other kinds of code (where you were building your own data
structures instead of using the Access/Jet engine), you would need
to create your own exception types, to handle your own exceptions
related to your data structures, but we use Access/Jet, and the
exception types are already defined. But either way, you would
still use the standard exception framework, and exceptions are
raised to the calling point.

The CalcValues example is an example where you are using your
own data structure, but it is only using a structure return value. Where
you want custom exceptions is where you have a structure as input,
and you want to return information about the structure: Standard VB
exceptions are only about standard VB types, and there would be
no standard way to return information like 'n needs to be >0 when
sType is sqrt'

A further limitation of VB is that it can only raise one kind of standard
exception object. You can't include things (like the CalcValues
structure) inside the exception object. This makes it less suitable for
nested or partial exceptions, which makes it less suitable for handling
functions like CalcValues, that do multiple different things.

But in practice, that is only part of the reason why you shouldn't
have functions like CalcValues that do multiple different things.

Even in languages like C++, where you can return a custom exception
object, you would not use a custom exception object just so that
you could have a CalcValues function. It is a rule that each function
should only do one thing.

(david)






"Geoff" <geoff[ at ]nospam.com> wrote in message
news:eBMOOhW3GHA.1796[ at ]TK2MSFTNGP06.phx.gbl...
> > You see this style of code when doing calls
> > to the Windows API...
>
> Yes, I know. I think there is also be a parallel with old DOS programs
that
> used to return errorlevels.
>
> > When calling Com objects, or when writing your own
> > code, you would expect the function to return the
> > structure, and exceptions like "non-numeric input" to be
> > returned as exceptions.
>
> How would you expect a VB function return exceptions?
>
> G
>
>
> <david[ at ]epsomdotcomdotau> wrote in message
> news:eBxCouP3GHA.2196[ at ]TK2MSFTNGP06.phx.gbl...
> > This is an example for a language that does not support
> > exceptions. You see this style of code when doing calls
> > to the Windows API, because the Windows API does
> > not export exceptions. Also, old style C did not have a
> > run-time supervisor, so old style C was written like this.
> >
> >
> > When calling Com objects, or when writing your own
> > code, you would expect the function to return the structure,
> > and exceptions like "non-numeric input" to be returned
> > as exceptions.
> >
> > (david)
> >
>
>
>


Home | Search | Terms | Imprint | Contact
Newsgroups Reader - provided by WiredBox.Net