|
|
Our Hot Pick: Rising Antivirus 2006 - Certified by TUV & Checkmark! Get 10% discount by entering this coupon code: ONDISCOUNT10
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
|
|
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
|
|
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 > > >
|
|
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 >> >> >>
|
|
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................
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 > > >
|
|
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) >
|
|
|
[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) >
|
|
I didn't mean to post this one!
G
|
|
|
[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) > > > > >
|
|
|