See also:
PassByReference and
AlternativesToPassByReference.
Mostly VisualBasic
I had to wrestle with the following code:
Private Sub cmdView_Click()
ShowPage m_url
End Sub
...
Private Sub ShowPage(url As String)
url = "http://" & url
... code to bring up a browser and point it to url omitted...
End Sub
The first time you click <view> you go to
http://www.foo.com, the second time the browser attempts to open
http://http://www.foo.com and complains.
The implicit
ByRef is to blame. The S
howPage routine should have been written
Private Sub ShowPage(ByVal url As String)
Though some (including me) would argue that altering the value of an argument is
BadPractice.
(I second that notion. -- JeffGrigg)
That is...
Private Sub ShowPage(ByVal hostName As String)
Dim url as String
url = "http://" & hostName
...etc...
End Sub
....
While working on
VisualBasic code, I routinely add explicit
ByRef and
ByVal prefixes to all parameters, so that none remain implicitly
ByRef.
Most
VisualBasic code does not change parameter values, in spite of the parameters defaulting to
ByRef, but showing one's intention in the interface reduces the chance of error.
Being an experienced
CeePlusPlus programmer, I'd like to pass "const" objects between
VisualBasic functions, but
ByVal isn't it. So I have to use
ByRef and just document the "constness" (or not) of my object usage.
--
JeffGrigg
In
LanguageOrientedProgramming a
ByRef in itself is not considered harmful, if it is used correctly. But in this case it is an
LopCrime, because nothing in the function name tells us about this hidden change. In the
ThelopLanguage there are special words that must be used to indicate such behaviour. It would not even be acceptable, if the function would be made "tolerant"
Private Sub ShowPage(url As String)
if Left$(url,7)<>"http://" then
url = "http://" & url
end if
... code to bring up a browser and point it to url omitted...
End Sub
eliminating the problem shown above in the second call.
This version
Private Sub ShowPage(url As String)
String url_complete
url_complete=url
if Left$(url_complete,7)<>"http://" then
url_complete = "http://" & url_complete
end if
... code to bring up a browser and point it to url_complete omitted...
End Sub
would also eliminate the quiet change of the parameter, but it is still unacceptable with respect to its name. Without having enough knowledge about the complete API environment I would suggest that the name should contain the words "Browser", "Url", "Show" or "Open", and optionally "Window", perhaps
Private Sub UrlOpenBrowserWindow(url As String)
String url_complete
url_complete =UrlRetUrlComplete(url)
... code to bring up a browser and point it to url_complete omitted...
End Sub
or
Private Sub BrowserOpenUrlWindow(url As String)
String url_complete
url_complete =UrlRetUrlComplete(url)
... code to bring up a browser and point it to url_complete omitted...
End Sub
if we assume that we want to deal with only one external default browser.
--
HelmutLeitner
Isn't the 'Url' in the method name redundant? The parameter name explicitly tells it expects a url. -- ThomasEyde
Agreed. I would write something like the following:
Private Function PrependHttp(PartialUrl As String) As String
PrependHttp = "http://" & PartialUrl
End Function
Private Sub OpenBrowserWindow(PartialUrl As String)
String CompleteUrl
CompleteUrl = PrependHttp(PartialUrl)
... code to bring up a browser and point it to CompleteUrl
End Function
This also avoids mixing
CamelCase with
UnderscoreCase, uses
NounsAndVerbs in suitable places. I'd also try to remove the temp Completed
Url if possible. --
MattRyall
See! ThingsWeHateAboutVbClassic,
VbTeachesBadHabits,
VbIsBadForNewbies,
VbIsGoodForCrapProgrammers (Choose your favorite! ;-)
There are additional confusions when VB
ByRef and
ByVal concepts are applied to objects:
In VB, many common kinds of objects that have default value properties and can be used directly as if they were those properties. For instance, a = Me.txtName does the same thing as Me.txtName.Value because (Value) is the default property for the class of Access.Control. When assigning object references, the Set keyword is used, so that case is unambiguous, but...
When a procedure accepts a parameter of Variant type, if an object instance supplied, the object is passed, and there's no convention to force the value to be used instead. This usually produces no symptoms, but let's say I'm adding a bunch of field values to a collection for use later, and then move to a new row in a recordset. If I say colValues.Add rst!Foo
Field, I've just added the field, not the value, and when I move to a new row, the field's value changes! This is a common class of coding error in VB.
When writing custom functions, other behaviors of VB lead us to believe that we can solve the problem in the case of a Variant parameter by using
ByVal. After all, if I try to pass 3 to a string argument by reference, I get an error, but if I pass by value, type conversion is automatically performed. Furthermore, an object reference is a reference, right? So
ByVal as opposed to
ByRef should force resolution of an object instance's default Value property, right? No, wrong.
What actually happens when you pass an object variable by value to a procedure that takes a Variant argument is simply that if the called procedure assigns a new reference to the parameter, that doesn't affect what object the passed variable now refers to after the procedure returns. If the parameter were
ByRef, then assigning a new object instance within the called procedure would also change the object pointed to by parameter variable in the caller.
Oh, and by the way, if you pass an object member as a parameter to a procedure (e.g. Foo(fld.Value) ), it always acts as
ByVal even if you explicitly said and intended
ByRef (in this case, meaning the calling procedure can't assign a value to fld.Value by assigning to the parameter). This is because
ByRef is implemented using pointers, but object properties are always retrieved behind the scenes using getter procedures, even if the members are defined as something like Public Foo
Member As String. Consequently, the reference that is passed to the procedure is always to the hidden, temporary variable that holds the value returned form the getter, not the the storage space of the member variable.
Mostly CeeLanguage/CeePlusPlus
In
CeeLanguage/
CeePlusPlus use
HungarianNotation and prefix pointers (references) with a "p" ("r"). Balance *'s with p's and you're good. --
SunirShah
In C++, use const and you don't have to worry about
HungarianNotation. In any case, there is usually no advantage in reusing a variable as shown above. You are allocating new memory in either case, why not just create a new variable name? --
WayneMack
To be fair,
CeeLanguage has long had this problem with char * strings, and C does not have the option of choosing
ByRef or
ByVal. It is only by convention that you agree not to modify the string.
True, so true. Tho' it's nice to have const now.
JavaProgrammers would argue that
const doesn't give guarantees. It is only by convention that you don't cast it away.
The
ConstQualifier (in C) must be
explicitly cast away (
CastingAwayConst). This forces you to think about the cast, and decide whether you are doing the right thing or not. In
CeeLanguage, const can never give cast-iron guarantees. In
JavaLanguage it could, but you don't need it because you can get the same result with
JavaInterfaces.
CategoryVisualBasic CategoryCee CategoryCpp