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

Passing arguments to function by reference - Good or Bad?

P: n/a
Just spent a happy 10 mins trying to understand a function I wrote sometime
ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween
Nov 13 '05 #1
Share this Question
Share on Google+
39 Replies


P: n/a
Personally, I don't think there's anything wrong with always learning (and
remembering again what you've learned before).
Surely everybody does in all walks of life.

And there are times when passing arguments by reference has been
considerably useful.

Others may disagree.

"Mike MacSween" <mi***************************@btinternet.com> wrote in
message news:42***********************@news.aaisp.net.uk.. .
Just spent a happy 10 mins trying to understand a function I wrote sometime ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween

Nov 13 '05 #2

P: n/a
rkc
Mike MacSween wrote:
Just spent a happy 10 mins trying to understand a function I wrote sometime
ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.


I've always thought that having byref be the default was, if not
bad, at least backwards.
Nov 13 '05 #3

P: n/a
"Mike MacSween" <mi***************************@btinternet.com> wrote in
message news:42***********************@news.aaisp.net.uk.. .
Just spent a happy 10 mins trying to understand a function I wrote
sometime ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween


By reference can cause you trouble. Look at the first sub, which might seem
OK at first glance. However, the TableExists function was written by some
idiot who changes the value of strTableName to "MSysAccessObjects" if the
table is found. So although I would guess my sub says 'if the table is
there - delete it' what it actaually does is 'if the table is there try to
delete a system table'. Now although this example is a bit extreme and the
attempt to delete "MSysAccessObjects" should fail anyway, I hope it
illustrates the general danger.

PS Was that your letter on BBC Radio 4's 'You and Yours' program a while ago
or just soemone with the same name?

Public Sub DeleteTable(strTableName As String)

On Error GoTo Err_Handler

If TableExists(strTableName) Then
CurrentDb.TableDefs.Delete strTableName
End If

Exit_Handler:
Exit Sub

Err_Handler:
MsgBox Err.Description, vbExclamation, "Error No: " & Err.Number
Resume Exit_Handler

End Sub

Private Function TableExists(strTableName As String) As Boolean

On Error GoTo Err_Handler

Dim dbs As DAO.Database
Dim tdf As DAO.TableDef

Set dbs = CurrentDb

For Each tdf In dbs.TableDefs
If tdf.Name = strTableName Then
TableExists = True
strTableName = "MSysAccessObjects"
Exit For
End If
Next tdf

Exit_Handler:

On Error Resume Next
Set tdf = Nothing
Set dbs = Nothing
Exit Function

Err_Handler:
MsgBox Err.Description, vbExclamation, "Error No: " & Err.Number
Resume Exit_Handler

End Function
Nov 13 '05 #4

P: n/a
Justin Hoffman wrote:
By reference can cause you trouble. Look at the first sub, which might seem
OK at first glance. However, the TableExists function was written by some
idiot who changes the value of strTableName to "MSysAccessObjects" if the
table is found. So although I would guess my sub says 'if the table is
there - delete it' what it actaually does is 'if the table is there try to
delete a system table'. Now although this example is a bit extreme and the
attempt to delete "MSysAccessObjects" should fail anyway, I hope it
illustrates the general danger.


It doesn't to me. Now, I'm suffering terribly from caffeine withdrawal
as I've abandoned my diet pepsi for Aquafina water, so I might be
missing something, but how else do you pass an argument to a function?

Other than making functions huge in size, calculating everything
redundantly for each function...

If I inherited and was maintaining the above example (code snipped) and
I didn't check to see where strTableName comes from (a simple search
project for the name of the function will work to find where the
function is embedded - menu items, are, of course a bit trickier) then I
deserve to have mSysAccessObjects deleted.... Ditto for a development
group leader that doesn't keep tabs on where the results of proc
development he's delegated out.

So, how else do you pass an argument? I hope I'm not sounding
confrontational (my apologies if I do), I just can't, at this moment
figure out how else to do it, unless it's something obvious I'm just
missing.
--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me
Nov 13 '05 #5

P: n/a
Per Mike MacSween:
Then remembered that arguments are passed by reference, by default.


Knowing nothing about the technical underpinnings, I pass parms ByVal whenever
possible.

Reason: somewhere in the few books I've read on "good" programming was the idea
that functions should be, among other things, independent. Seems to me like a
parm passed ByRef introduces the complication of somebody else being able to
affect the value in question.

Also, I always explicitly code ByVal or ByRef and push all the ByRefs to the end
of the parm list.
--
PeteCresswell
Nov 13 '05 #6

P: n/a
"Tim Marshall" <TI****@PurplePandaChasers.Moertherium> wrote in message
news:d8**********@coranto.ucs.mun.ca...
Justin Hoffman wrote:
By reference can cause you trouble. Look at the first sub, which might
seem OK at first glance. However, the TableExists function was written
by some idiot who changes the value of strTableName to
"MSysAccessObjects" if the table is found. So although I would guess my
sub says 'if the table is there - delete it' what it actaually does is
'if the table is there try to delete a system table'. Now although this
example is a bit extreme and the attempt to delete "MSysAccessObjects"
should fail anyway, I hope it illustrates the general danger.


It doesn't to me. Now, I'm suffering terribly from caffeine withdrawal as
I've abandoned my diet pepsi for Aquafina water, so I might be missing
something, but how else do you pass an argument to a function?

Other than making functions huge in size, calculating everything
redundantly for each function...

If I inherited and was maintaining the above example (code snipped) and I
didn't check to see where strTableName comes from (a simple search project
for the name of the function will work to find where the function is
embedded - menu items, are, of course a bit trickier) then I deserve to
have mSysAccessObjects deleted.... Ditto for a development group leader
that doesn't keep tabs on where the results of proc development he's
delegated out.

So, how else do you pass an argument? I hope I'm not sounding
confrontational (my apologies if I do), I just can't, at this moment
figure out how else to do it, unless it's something obvious I'm just
missing.
--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me

Hi Tim
A perfectly valid question - and if you want to really see it work, just
copy the example into a new module, create a dummy table and run DeleteTable
"MyTable" which stupidly tries to delete the system table.
Now alter the sub so that you put the word ByVal in front of the variable:
DeleteTable(ByVal strTableName As String)
Now when you run the sub, this can't happen. strTableName is passed by
value (just a copy - so the original can't be altered) and not by reference
where the sub may change the actual value.
Nov 13 '05 #7

P: n/a

"Justin Hoffman" <j@b.com> wrote in message
news:d8**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com...
"Tim Marshall" <TI****@PurplePandaChasers.Moertherium> wrote in message
news:d8**********@coranto.ucs.mun.ca...
Justin Hoffman wrote:
By reference can cause you trouble. Look at the first sub, which might
seem OK at first glance. However, the TableExists function was written
by some idiot who changes the value of strTableName to
"MSysAccessObjects" if the table is found. So although I would guess my
sub says 'if the table is there - delete it' what it actaually does is
'if the table is there try to delete a system table'. Now although this
example is a bit extreme and the attempt to delete "MSysAccessObjects"
should fail anyway, I hope it illustrates the general danger.


It doesn't to me. Now, I'm suffering terribly from caffeine withdrawal
as I've abandoned my diet pepsi for Aquafina water, so I might be missing
something, but how else do you pass an argument to a function?

Other than making functions huge in size, calculating everything
redundantly for each function...

If I inherited and was maintaining the above example (code snipped) and I
didn't check to see where strTableName comes from (a simple search
project for the name of the function will work to find where the function
is embedded - menu items, are, of course a bit trickier) then I deserve
to have mSysAccessObjects deleted.... Ditto for a development group
leader that doesn't keep tabs on where the results of proc development
he's delegated out.

So, how else do you pass an argument? I hope I'm not sounding
confrontational (my apologies if I do), I just can't, at this moment
figure out how else to do it, unless it's something obvious I'm just
missing.
--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me

Hi Tim
A perfectly valid question - and if you want to really see it work, just
copy the example into a new module, create a dummy table and run
DeleteTable "MyTable" which stupidly tries to delete the system table.
Now alter the sub so that you put the word ByVal in front of the variable:
DeleteTable(ByVal strTableName As String)
Now when you run the sub, this can't happen. strTableName is passed by
value (just a copy - so the original can't be altered) and not by
reference where the sub may change the actual value.

Sorry - the ByVal should of course appear in the TableExists function, as
this was the naughty piece of coding which was altering the value:
Private Function TableExists(ByVal strTableName As String) As Boolean
Although having it in the DeleteTable wouldn't be a bad idea either.
Nov 13 '05 #8

P: n/a
Justin Hoffman wrote:
Hi Tim
A perfectly valid question - and if you want to really see it work, just
copy the example into a new module, create a dummy table and run
DeleteTable "MyTable" which stupidly tries to delete the system table.
Now alter the sub so that you put the word ByVal in front of the variable:
DeleteTable(ByVal strTableName As String)
Now when you run the sub, this can't happen. strTableName is passed by
value (just a copy - so the original can't be altered) and not by
reference where the sub may change the actual value.


Sorry - the ByVal should of course appear in the TableExists function, as
this was the naughty piece of coding which was altering the value:
Private Function TableExists(ByVal strTableName As String) As Boolean
Although having it in the DeleteTable wouldn't be a bad idea either.


Ah, OK, thanks for the clarification. I thought we were talking about
arguments, period! 8)

--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me
Nov 13 '05 #9

P: n/a
On Tue, 7 Jun 2005 10:42:36 +0100, "Mike MacSween"
<mi***************************@btinternet.com> wrote:
Just spent a happy 10 mins trying to understand a function I wrote sometime
ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween


My 2c on ByRef.

Well, yes, passing parameters by reference by default is somewhat dangerous.
I think it is the default, though, because it is also generally more
efficient. That doesn't make it right, but it might explain why MS did it
that way, particularly since computers were a lot slower when VB 1.0 came out.

For a programmer with good habits (well - if -all- programmers who maintain
the project have good habits), the passing of parameters by reference should
not be a problem.

The reason I say this is that it is bad style to ever write a value to a
parameter except in the odd case where you do actually choose to use ByRef for
returning a value to the caller, which is sometimes appropriate. The reason
for this rule is that one variable should never do more than one thing. If
one variable is both a parameter for getting a value into a procedure and a
buffer to hold working data within the procedure, that's more than one thing.

Now - notice the part above about "if -all- programmers who maintain the
project ..."? Well, we should never strive to write programs that are only
easy to maintain by experts. That's why it might be good to just not use
ByRef parameters unless you mean it or unless you are optimizing a slow part
of the code. In special cases, such as when processing strings in a loop, you
might preemptively choose to pass string parameters by reference to save the
hassle of fighting with performance problems later.
Nov 13 '05 #10

P: n/a
On Tue, 07 Jun 2005 08:07:58 -0700, Steve Jorgensen <no****@nospam.nospam>
wrote:

....

My 2c on ByRef.

Well, yes, passing parameters by reference by default is somewhat dangerous.
I think it is the default, though, because it is also generally more
efficient. That doesn't make it right, but it might explain why MS did it
that way, particularly since computers were a lot slower when VB 1.0 came out.

For a programmer with good habits (well - if -all- programmers who maintain
the project have good habits), the passing of parameters by reference should
not be a problem.

The reason I say this is that it is bad style to ever write a value to a
parameter except in the odd case where you do actually choose to use ByRef for
returning a value to the caller, which is sometimes appropriate. The reason
for this rule is that one variable should never do more than one thing. If
one variable is both a parameter for getting a value into a procedure and a
buffer to hold working data within the procedure, that's more than one thing.

Now - notice the part above about "if -all- programmers who maintain the
project ..."? Well, we should never strive to write programs that are only
easy to maintain by experts. That's why it might be good to just not use
ByRef parameters unless you mean it or unless you are optimizing a slow part
of the code. In special cases, such as when processing strings in a loop, you
might preemptively choose to pass string parameters by reference to save the
hassle of fighting with performance problems later.


By the way, I always wondered why MS didn't provide a parameter style that is
by reference, and read-only from within the procedure (compile error if you
try), so it is guaranteed to be efficient for handling strings and arrays, but
also be guaranteed to have no side effects.
Nov 13 '05 #11

P: n/a
On Tue, 07 Jun 2005 08:07:58 -0700, Steve Jorgensen <no****@nospam.nospam>
wrote:
On Tue, 7 Jun 2005 10:42:36 +0100, "Mike MacSween"
<mi***************************@btinternet.com> wrote:
Just spent a happy 10 mins trying to understand a function I wrote sometime
ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween


My 2c on ByRef.

Well, yes, passing parameters by reference by default is somewhat dangerous.
I think it is the default, though, because it is also generally more
efficient. That doesn't make it right, but it might explain why MS did it
that way, particularly since computers were a lot slower when VB 1.0 came out.

For a programmer with good habits (well - if -all- programmers who maintain
the project have good habits), the passing of parameters by reference should
not be a problem.

The reason I say this is that it is bad style to ever write a value to a
parameter except in the odd case where you do actually choose to use ByRef for
returning a value to the caller, which is sometimes appropriate. The reason
for this rule is that one variable should never do more than one thing. If
one variable is both a parameter for getting a value into a procedure and a
buffer to hold working data within the procedure, that's more than one thing.

Now - notice the part above about "if -all- programmers who maintain the
project ..."? Well, we should never strive to write programs that are only
easy to maintain by experts. That's why it might be good to just not use
ByRef parameters unless you mean it or unless you are optimizing a slow part
of the code. In special cases, such as when processing strings in a loop, you
might preemptively choose to pass string parameters by reference to save the
hassle of fighting with performance problems later.


A factorial function makes a good example...

Public Function Factorial(FactorialOf As Long) As Long

Factorial = 1

While FactorialOf > 1
Factorial = Factorial * FactorialOf
FactorialOf = FactorialOf - 1
Wend

End Function

To my mind, this procedure has 2 problems. First, it uses an input parameter
variable as a buffer for intermediate values, and second, it uses the function
name as a variable. The first issue is aproblem both because one variable is
being used for 2 purposes, and because this will change the value of the
variable passed to Factorial. The second is a problem because, although VB
does work that way, it's confusing when you use a function name on the right
side of an expression - it's even worse if the procedure has no parameters or
all parameters are optional.

The side effect problem above can be fixed by making the parameter ByVal, but
to fix the style, something like this would be requried...

Public Function Factorial(FactorialOf As Long) As Long

Dim lngResult As Long
Dim lngMult As Long

lngResult = 1

For lngMult = 2 to FactorialOf
lngResult = lngResult * lngMult
Next

Factorial = lngResult
End Function

This is totally safe, and it's good style, except that we should still now
cover our asses, and change FactorialOf to be ByVal in case a future
maintainer (possibly ourselves after too little caffiene or brain surgery)
reoptimizes the procedure, and in defiance of good style, again includes a
write to the FactorialOf variable.
Nov 13 '05 #12

P: n/a
"Justin Hoffman" <j@b.com> wrote in message
news:d8**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com...
"Mike MacSween" <mi***************************@btinternet.com> wrote in PS Was that your letter on BBC Radio 4's 'You and Yours' program a while
ago or just soemone with the same name?


I am indeed he, the harrasser of Radio 4 whiners! MacSween of that ilk.
Nov 13 '05 #13

P: n/a
Thanks for your advice folks. So is there any argument passing equivalent to
Option Explicit? So that you HAVE to declare as either ByVal or ByRef.

"Mike MacSween" <mi***************************@btinternet.com> wrote in
message news:42***********************@news.aaisp.net.uk.. .
Just spent a happy 10 mins trying to understand a function I wrote
sometime ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween

Nov 13 '05 #14

P: n/a
Mike MacSween wrote:
Just spent a happy 10 mins trying to understand a function I wrote sometime
ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween


Naming conventions help here. Prefixing parameters with a "p" for
example (like the ol' L/R conventions, I think R on his own still does)
makes parameters show up in the middle of a procedure, e.g.

Function MyFunction(pstrSomething as string)
... some code
pstrSomething = strSomethingElse

Even a few hundred lines down the code that last line should stand out
as a parameter being assigned to something, should sound alarms somewhere.

--
[OO=00=OO]
Nov 13 '05 #15

P: n/a
Steve Jorgensen wrote:
Now - notice the part above about "if -all- programmers who maintain the
project ..."? Well, we should never strive to write programs that are only
easy to maintain by experts. That's why it might be good to just not use
ByRef parameters


Folks, is there a good primer on what byref and byval are all about?
I've never used them except in the occasional circumstance when my
procedures have generated an error and the err.help told me that byref
was required.

--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me
Nov 13 '05 #16

P: n/a
"Mike MacSween" <mi***************************@btinternet.com> wrote in
message news:42***********************@news.aaisp.net.uk.. .
"Justin Hoffman" <j@b.com> wrote in message
news:d8**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com...
"Mike MacSween" <mi***************************@btinternet.com> wrote in

PS Was that your letter on BBC Radio 4's 'You and Yours' program a while
ago or just soemone with the same name?


I am indeed he, the harrasser of Radio 4 whiners! MacSween of that ilk.

When working from home I always try to wait until the news at 1pm before
going to the kitchen for lunch. On bad days I go a bit earlier, and on
really bad days I switch on the radio and remind myself of why I try and
hold out until one. It is even worse than Woman's Hour.
Nov 13 '05 #17

P: n/a
Per Tim Marshall:
Now, I'm suffering terribly from caffeine withdrawal
as I've abandoned my diet pepsi for Aquafina water


If it doesn't work out, try switching to coffee and mixing regular/decaf and
reducing the amount of regular over time. i.e. tapering off vs cold turkey.
Might be able to do the same thing by mixing Diet Pepsi with some sort of
carbonated (dunno if Aquafina is carbonated...) water.
--
PeteCresswell
Nov 13 '05 #18

P: n/a
Justin Hoffman wrote:
When working from home I always try to wait until the news at 1pm before
going to the kitchen for lunch. On bad days I go a bit earlier, and on
really bad days I switch on the radio and remind myself of why I try and
hold out until one. It is even worse than Woman's Hour.


In our office we would all gather round the radio at around 3pm when
"Not the News" was on Radio 1 :-)

--
[OO=00=OO]
Nov 13 '05 #19

P: n/a
Tim Marshall wrote:
Steve Jorgensen wrote:
Now - notice the part above about "if -all- programmers who maintain the
project ..."? Well, we should never strive to write programs that are
only
easy to maintain by experts. That's why it might be good to just not use
ByRef parameters

Folks, is there a good primer on what byref and byval are all about?
I've never used them except in the occasional circumstance when my
procedures have generated an error and the err.help told me that byref
was required.


ByRef passes a reference (pointer) to the variable so that variable if
modified in the called procedure would return the modified contents back
to the calling procedure.

ByVal passes just the value of the variable to the procedure, in essense
it creates a new variable who's scope is just for the called procedure.

--
[OO=00=OO]
Nov 13 '05 #20

P: n/a
"Justin Hoffman" <j@b.com> wrote in
news:d8**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com:
By reference can cause you trouble. Look at the first sub, which
might seem OK at first glance. However, the TableExists function
was written by some idiot who changes the value of strTableName to
"MSysAccessObjects" if the table is found. So although I would
guess my sub says 'if the table is there - delete it' what it
actaually does is 'if the table is there try to delete a system
table'. Now although this example is a bit extreme and the
attempt to delete "MSysAccessObjects" should fail anyway, I hope
it illustrates the general danger.


Er, the "general danger" you've outlined is that badly written code
can have unforeseen results.

The error would be there regardless of whether or not the parameter
were passed ByRef or ByVal, it's just that with ByRef, the error can
cause confusion outside the subroutine itself (though the table
involved can't be deleted -- it will just throw an error).

But you've definitely demonstrated that bad code is bad.

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

P: n/a
Trevor Best <no****@besty.org.uk> wrote in
news:42***********************@news.zen.co.uk:
Tim Marshall wrote:
Steve Jorgensen wrote:
Now - notice the part above about "if -all- programmers who
maintain the project ..."? Well, we should never strive to
write programs that are only
easy to maintain by experts. That's why it might be good to
just not use ByRef parameters

Folks, is there a good primer on what byref and byval are all
about? I've never used them except in the occasional circumstance
when my procedures have generated an error and the err.help told
me that byref was required.


ByRef passes a reference (pointer) to the variable so that
variable if modified in the called procedure would return the
modified contents back to the calling procedure.


What this means is that the subroutine that is passed an argument
ByRef can alter that value internally and after control passes back
to the code that called it, the value will remain changed.

Private Sub IncrementValue(ByRef lngValue As Long)
lngValue = lngValue + 1
End Sub

Private Sub LeaveMeAlone(ByVal lngValue As Long)
lngValue = lngValue + 1
End Sub

Dim lngInitialValue as Long
Dim lngPassedValue as Long

lngInitialValue = 10
lngPassedValue = lngInitialValue

Call LeaveMeAlone(lngPassedValue)
Debug.Print lngPassedValue = lngInitialValue ' Returns TRUE

Call IncrementValue(lngPassedValue)
Debug.Print lngPassedValue = lngInitialValue ' Returns FALSE
ByVal passes just the value of the variable to the procedure, in
essense it creates a new variable who's scope is just for the
called procedure.


You have to be careful with object variables. I don't know what
would happen if you passed a recordset ByVal.

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

P: n/a
On Wed, 08 Jun 2005 03:41:55 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:

....

You have to be careful with object variables. I don't know what
would happen if you passed a recordset ByVal.


As a result of some code od mine having unpredicted side effects, I did some
experiments to determine exactly what does happen when you pass an object
reference vs by value, and it's good to understand.

First, most important point - if you pass an object variable by value to a
Variant parameter, the parameter will still contain a reference to the object,
even if the object has a default value property, such as a Textbox control
object. This can be really important because if you pass the control as a
parameter to a function that then passes it to the Add method of a VBA
Collection, you did -not- store the value, you stored the control. When the
user moves to a new record on the form, its value will change in the
collection! Futhermore, when the form is closed, the collection item will be
invalid.

it is not safe to pass a control or a field to the Value argument below...

Private mcolForLaterBuffer As VBA.Collection

Public Sub SaveForLater(ByVal Value As Variant, Key As String)
mcolForLaterBuffer.Add Key:=Key, Value:=Value
End Sub

What ByVal turns out to mean for objects, whether passed to variant parameters
or object parameters is that a new copy of the reference to the object is
created, and the reference count increases by one. This is just like setting
a variable to an object reference using Set. Passing by reference, on the
other hand, the called function shares the object reference that was passed,
so assigning a new object to the parameter variable within the procedure
replaces the reference in the variable passed by the calling procedure as
well.

The key here is that an object reference and ByRef have completely orthogonal
meanings.
Nov 13 '05 #23

P: n/a

"David W. Fenton" <dX********@bway.net.invalid> wrote in message
news:Xn**********************************@24.168.1 28.86...
"Justin Hoffman" <j@b.com> wrote in
news:d8**********@nwrdmz01.dmz.ncs.ea.ibs-infra.bt.com:
By reference can cause you trouble. Look at the first sub, which
might seem OK at first glance. However, the TableExists function
was written by some idiot who changes the value of strTableName to
"MSysAccessObjects" if the table is found. So although I would
guess my sub says 'if the table is there - delete it' what it
actaually does is 'if the table is there try to delete a system
table'. Now although this example is a bit extreme and the
attempt to delete "MSysAccessObjects" should fail anyway, I hope
it illustrates the general danger.


Er, the "general danger" you've outlined is that badly written code
can have unforeseen results.

The error would be there regardless of whether or not the parameter
were passed ByRef or ByVal, it's just that with ByRef, the error can
cause confusion outside the subroutine itself (though the table
involved can't be deleted -- it will just throw an error).

But you've definitely demonstrated that bad code is bad.

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


What I am pointing out is that there is a difference between:
I guess TableExists(strTableName) won't alter the value of strTableName -
because that would be silly.
I can guarantee the function can't alter strTableName because it is passed
by value
If a project is coded by more than one author you *might like to bear in
mind the possibility that*, unless you pass your variables by value, another
person's function can change their values - although the bugs are usually
more subtle than the example given. Alternatively, you could completely
disregard this possibility in the sure knowledge that this would never
happen in one of your applications.
Having said all that, my real-life TableExists function accepts the table
name by reference, not by value. But as the topic under discussion is 'By
Ref - good or bad?', I thought it fair to point this out.
Nov 13 '05 #24

P: n/a
Steve Jorgensen wrote:
On Wed, 08 Jun 2005 03:41:55 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
You have to be careful with object variables. I don't know what
would happen if you passed a recordset ByVal.


Trevor, David (especially for the illustrative example) & Steve, thanks
very much. You know, I had absolutely no idea of exactly what
ByVal/ByRef did and after reading your posts, I also did some hunting on
the help files of A2003. I was shocked to realize byRef is the default!
After all this time, I had no idea a variable passed to one function
is itself changed in the calling proc. Good lord...
--
Tim http://www.ucs.mun.ca/~tmarshal/
^o<
/#) "Burp-beep, burp-beep, burp-beep?" - Quaker Jake
/^^ "Whatcha doin?" - Ditto "TIM-MAY!!" - Me
Nov 13 '05 #25

P: n/a
Great help here. Thanks folks.

So a routine called mrm_gGetMailMergeDocs queries a table which has a list
of query/word template pairs which are executed by mail merge routine. Which
pair is returned, depends on the letter 'type' and 2 of the properties of
the course on the current form (what type of course and whether local or
distant). If a pair is found then that's what gets used, otherwise a default
supplied at run time.

I want to get 2 things back, so a function returning a value won't do it,
hence the ByRef

Would I have been better using 2 functions? Or a function that returns an
object and make this some sort of class thing?

Or more likely, wrapping this all into the same function? (Yes, that's the
answer, thanks folks)

Here's (the relevant) code then. See if you think this an appropriate use:

Private Sub cmdDiplomas_Click()
Dim strQueryName As String 'which will be passed to
mrm_gGetMailMergeDocs by Ref
Dim strTemplateName As String 'ditto
Dim intResult As Integer

390 intResult = mrm_gGetMailMergeDocs(strQueryName, strTemplateName,
"DIP")

400 Select Case intResult
Case 1 'means none found
410 Call MailMerge("qryDiplomas", "diplomas.dot") 'so supply the
default
420 Case 0 'means found
430 Call MailMerge(strQueryName, strTemplateName) 'call MailMerge
with the vars altered by mrm_getMailMergeDocs
440 Case 2
450 MsgBox "Error. Contact the system administrator. There are
multiple mail merges defined"
460 Case Else
470 MsgBox "Error in Mail Merge routine. Contact the system admin"
480 End Select

End Sub

Function mrm_gGetMailMergeDocs(inQueryName As String, inTemplateName As
String, strLetterType As String) As Integer
' Comments : arguments are passed in BY REFERENCE
' which is how they are getting 'passed back' to the calling
procedure.
Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset

580 Set db = CurrentDb()
590 Set qdf = db.QueryDefs("qryGetMailMergeDocs")

'test for non-open form needed here
600 qdf("[Forms]![frmCourses]![SatOrLocal]") =
[Forms]![frmCourses]![SatOrLocal]
610 qdf("[Forms]![frmCourses]![CourseTypeID]") =
[Forms]![frmCourses]![CourseTypeID]
620 qdf("[Enter Letter Type]") = strLetterType

630 Set rst = qdf.OpenRecordset

640 If rst.BOF And rst.EOF Then 'no records
650 mrm_gGetMailMergeDocs = 1
660 Else
670 rst.MoveLast
680 If rst.RecordCount > 1 Then 'too many records. This should never
happen.
690 mrm_gGetMailMergeDocs = 2
700 Else
710 inQueryName = rst!QueryName.Value ' inQueryName passed in by
reference remember
720 inTemplateName = rst!TemplateName.Value 'ditto
730 mrm_gGetMailMergeDocs = 0 'for success
740 End If
750 End If

[error handler snipped]

End Function

"Mike MacSween" <mi***************************@btinternet.com> wrote in
message news:42***********************@news.aaisp.net.uk.. .
Just spent a happy 10 mins trying to understand a function I wrote
sometime ago.

Then remembered that arguments are passed by reference, by default.

Does the fact that this slowed me down indicate:

a) That I don't know enough

b) Passing arguments by ref is bad

c) A combination of the above.

Yours, Mike Macsween


Nov 13 '05 #26

P: n/a
Tim Marshall <TI****@PurplePandaChasers.Moertherium> wrote in
news:d8**********@coranto.ucs.mun.ca:
Steve Jorgensen wrote:
On Wed, 08 Jun 2005 03:41:55 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
You have to be careful with object variables. I don't know what
would happen if you passed a recordset ByVal.


Trevor, David (especially for the illustrative example) & Steve,
thanks very much. You know, I had absolutely no idea of exactly
what ByVal/ByRef did and after reading your posts, I also did some
hunting on the help files of A2003. I was shocked to realize
byRef is the default!
After all this time, I had no idea a variable passed to one
function
is itself changed in the calling proc. Good lord...


Well, it's only changed if the called code changes it.

As others have pointed out, there is no good reason for subroutines
to act upon the parameter variable at all, unless the intent really
*is* for that parameter to be used for passing information back to
the calling code context.

If there's only one variable being passed that needs a changed value
back, then you really ought to have a Function(), instead, and the
function will return the changed value.

However, in some cases, you actually need to get two or more
variables back, and in that case, a function would not work (unless
you did something like returning a string with multiple delimited
return values, and then parsed those out -- ick!), and a subroutine
with multiple ByRef parameters is just the ticket.

Again, the problem is caused *not* by passing ByRef, it's caused by
acting upon the parameter within the subroutine when that is not a
desired requirement of the code.

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

P: n/a
On Wed, 08 Jun 2005 20:08:03 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:
Tim Marshall <TI****@PurplePandaChasers.Moertherium> wrote in
news:d8**********@coranto.ucs.mun.ca:
Steve Jorgensen wrote:
On Wed, 08 Jun 2005 03:41:55 GMT, "David W. Fenton"
<dX********@bway.net.invalid> wrote:

You have to be careful with object variables. I don't know what
would happen if you passed a recordset ByVal.
Trevor, David (especially for the illustrative example) & Steve,
thanks very much. You know, I had absolutely no idea of exactly
what ByVal/ByRef did and after reading your posts, I also did some
hunting on the help files of A2003. I was shocked to realize
byRef is the default!
After all this time, I had no idea a variable passed to one
function
is itself changed in the calling proc. Good lord...


Well, it's only changed if the called code changes it.

As others have pointed out, there is no good reason for subroutines
to act upon the parameter variable at all, unless the intent really
*is* for that parameter to be used for passing information back to
the calling code context.

If there's only one variable being passed that needs a changed value
back, then you really ought to have a Function(), instead, and the
function will return the changed value.

However, in some cases, you actually need to get two or more
variables back, and in that case, a function would not work (unless
you did something like returning a string with multiple delimited
return values, and then parsed those out -- ick!), and a subroutine
with multiple ByRef parameters is just the ticket.


Sometimes (not always), this is a sign that a class, or in some cases, a user
defined type would be helpful.
Again, the problem is caused *not* by passing ByRef, it's caused by
acting upon the parameter within the subroutine when that is not a
desired requirement of the code.


However, it is helpful for peace of mind when to see the ByVal and know there
can be no side effects, no matter what the code does. This also clarifies
that the procedure has no -intended- side effects on the parameter.
Nov 13 '05 #28

P: n/a
On Wed, 8 Jun 2005 17:24:47 +0100, "Mike MacSween"
<mi***************************@btinternet.com> wrote:
Great help here. Thanks folks.

So a routine called mrm_gGetMailMergeDocs queries a table which has a list
of query/word template pairs which are executed by mail merge routine. Which
pair is returned, depends on the letter 'type' and 2 of the properties of
the course on the current form (what type of course and whether local or
distant). If a pair is found then that's what gets used, otherwise a default
supplied at run time.

I want to get 2 things back, so a function returning a value won't do it,
hence the ByRef

Would I have been better using 2 functions? Or a function that returns an
object and make this some sort of class thing?

You are corrrect that ByRef parameters can do the job, but since you have used
a single term "query/word template pair" to describe what comes back, that's a
good sign that it would be better to create a user defined type or a class to
handle the data - especially, since you could end up wanting to associate even
more information with the item, and you won't want to have to change all the
code that deals with it to handle that (just the code that uses the new item).

(I guess I like run-on sentences)

Or more likely, wrapping this all into the same function? (Yes, that's the
answer, thanks folks)


Making one function do more things is rarely a good thing, though you're right
that if the coupling between 2 things is complex, perhaps, they are not really
separate things.

Nov 13 '05 #29

P: n/a
rkc
Mike MacSween wrote:
Great help here. Thanks folks.

So a routine called mrm_gGetMailMergeDocs queries a table which has a list
of query/word template pairs which are executed by mail merge routine. Which
pair is returned, depends on the letter 'type' and 2 of the properties of
the course on the current form (what type of course and whether local or
distant). If a pair is found then that's what gets used, otherwise a default
supplied at run time.

I want to get 2 things back, so a function returning a value won't do it,
hence the ByRef

Would I have been better using 2 functions? Or a function that returns an
object and make this some sort of class thing?


I would put all that in a class making the two byref parameters
along with intResult properties of the class. That would reduce
the needed parameters to strLetterType and make the whole thing
easily re-usable and I think, easier to understand.
Nov 13 '05 #30

P: n/a
"rkc" <rk*@rochester.yabba.dabba.do.rr.bomb> wrote in message
news:5f*****************@twister.nyroc.rr.com...
I would put all that in a class making the two byref parameters
along with intResult properties of the class. That would reduce
the needed parameters to strLetterType and make the whole thing
easily re-usable and I think, easier to understand.


Thanks Rick

I considered that. Not sure. I'll talk myself through it out loud.

I think of objects as 'being' things, whereas this looks more like a 'doing'
thing.

At the moment there are 3 sort of procedures:

1. MailMerge(). Which wants a query and word dot. And merges them! Though
the query is usually parameterized, and those parameters are usually, but
not always, based upon an open form.

2. mrm_gGetMailMergeDocs(). Which takes 3 arguments, strQuery, strTemplate
(the ByRef ones which are 'passed back' to the calling code) and letterType,
which tells the routine what letter type to look for. It interrogates a
table that for each course type, course location (local or satellite) and
letter type contains a query name and a word template name. This function's
real return is an integer - success,failure, or some sort of predictable
error condition indicators. But this function contains hard coded
form!control!values. That looks bad.

3. The actual calling code. Which says something like 'if you find a
query/template pair use it, otherwise here's the defaults'.

I can see that all being wrapped into one thing. Or at least the last two.

newMailMerge (defQuery, defTemplate, CourseID)

The CourseID (index of each individual course) will give me the CourseTypeID
and the location (whether Satellite or local). So the routine can now
interrogate the table, find a query/template pair, use them, or if it
doesn't find them use the supplied defaults. Even better make the CourseID
the first parameter and make the other two optional. At the moment they are
always saved queries. But no reason why it couldn't be SQL strings.

But at the moment I can't see a massive advantage in making this an object.
But let me think:

dim myMailMerge as new MailMerge(5) 'the constuctor needs a course ID?

If myMailMerge.defaultsExist = true then
Else
myMailMerge.query = qryGetTheStudentsForDiabetesCourses
myMailMerge.template = "bigMailMerge.dot"
end if

myMailMerge.Preview

or maybe

myMailMerge.goPrint

Am I on the right lines?

Mike
Nov 13 '05 #31

P: n/a
rkc
Mike MacSween wrote:
At the moment there are 3 sort of procedures: 2. mrm_gGetMailMergeDocs(). Which takes 3 arguments, strQuery, strTemplate
(the ByRef ones which are 'passed back' to the calling code) and letterType,
which tells the routine what letter type to look for. It interrogates a
table that for each course type, course location (local or satellite) and
letter type contains a query name and a word template name. This function's
real return is an integer - success,failure, or some sort of predictable
error condition indicators. But this function contains hard coded
form!control!values. That looks bad.
This is what I was suggesting be written as a class. An object that
takes a letter type and queries a data source for a query and template.

Using your function, something like the following:

<clsMailMergeParameters>
private mQueryName as string
private mTemplateName as string
private mResult as integer

Public Property Get QueryName As String
QueryName = mQueryName
End Property

Public Property Get Template As String
Template = mTemplate
End Property

Public Property Get Result As Integer
Result = mResult
End Property

Private Function GetMailMergeDocs(strLetterType As String) As Integer

Dim db As DAO.Database
Dim qdf As DAO.QueryDef
Dim rst As DAO.Recordset

Set db = CurrentDb()
Set qdf = db.QueryDefs("qryGetMailMergeDocs")
qdf("[Forms]![frmCourses]![SatOrLocal]") =
[Forms]![frmCourses]![SatOrLocal]
qdf("[Forms]![frmCourses]![CourseTypeID]") =
[Forms]![frmCourses]![CourseTypeID]
qdf("[Enter Letter Type]") = strLetterType

Set rst = qdf.OpenRecordset

If rst.BOF And rst.EOF Then
mResult = 1
Else
rst.MoveLast
If rst.RecordCount > 1 Then
mResult = 2
Else
mQueryName = rst!QueryName.Value
mTemplateName = rst!TemplateName.Value
mResult = 0
End If
End If

'Clean up
End Function
</clsMailMergeParameters>

At first glance that doesn't look like much, but it has benefits.
It's self contained. It eliminates having to create three variables
in the calling code. If you decide to build a MailMerge class it
could be used as a private member of that class. If not here's a
driver based on your select case code:

Private Sub cmdDiplomas_Click()
Call DiplomasMailMergeDriver()
End Sub

Sub DiplomasMailMergeDriver
Dim mmp as clsMailMergeParameters
Set mmp = New clsMailMergeParameters
With mmp
.GetMailMergeDocs "BIP"

Select Case .Result
Case 1 'means none found
Call MailMerge("qryDiplomas", "diplomas.dot")
Case 0 'success
Call MailMerge(.QueryName, .TemplateName)
Case 2
MsgBox "Error. Contact the system...
Case Else
MsgBox "Error in Mail Merge routine...
End Select
End With
Set mmp = Nothing
End Sub
But at the moment I can't see a massive advantage in making this an object.
But let me think:

dim myMailMerge as new MailMerge(5) 'the constuctor needs a course ID?

If myMailMerge.defaultsExist = true then
Else
myMailMerge.query = qryGetTheStudentsForDiabetesCourses
myMailMerge.template = "bigMailMerge.dot"
end if

myMailMerge.Preview

or maybe

myMailMerge.goPrint

Am I on the right lines?


I think so. But then I don't think of a class as something for
special occasions. I think of them as how to write code.

Nov 13 '05 #32

P: n/a

"rkc" <rk*@rochester.yabba.dabba.do.rr.bomb> wrote in message
news:RN*****************@twister.nyroc.rr.com...
Mike MacSween wrote:
At the moment there are 3 sort of procedures:

2. mrm_gGetMailMergeDocs(). Which takes 3 arguments, strQuery,
strTemplate (the ByRef ones which are 'passed back' to the calling code)
and letterType, which tells the routine what letter type to look for. It
interrogates a table that for each course type, course location (local or
satellite) and letter type contains a query name and a word template
name. This function's real return is an integer - success,failure, or
some sort of predictable error condition indicators. But this function
contains hard coded form!control!values. That looks bad.


This is what I was suggesting be written as a class. An object that
takes a letter type and queries a data source for a query and template.

Using your function, something like the following:

<clsMailMergeParameters>
private mQueryName as string
private mTemplateName as string
private mResult as integer

Public Property Get QueryName As String
QueryName = mQueryName
End Property

Public Property Get Template As String
Template = mTemplate
End Property

Public Property Get Result As Integer
Result = mResult
End Property


Thanks Rick. So those Properties. Is a 'Property' of a class in Access
equivalent to a Public method accessing a private variable in other OOP
languages?
Nov 13 '05 #33

P: n/a
I'm late on this, but I would like to point out a couple of things just
the same.

I used to use ByVal religiously, and have found that I'm much happier
using it to "protect" variables. By stating "ByVal" in the argument
list, I can tell which variables risk being changed, or need to be
passed regardless of their type.

The opposite could just as easily be true, of course--seeing ByRef
could mean that a variable *was* to be changed. But I guess since
ByRef is the default anyway, I learned to do it the other way.

The trade-off is that you get a nice debugging aid--VBA will tell you
if you're passing an invalid argument ByRef, but (naturally) not ByVal.
Also, I believe it was in Getz & co.'s handbook that it was pointed out
that every ByVal argument causes double memory use and slower
execution, since passing by value is just an implicit creation of a
local copy of the variable, so that

Function Foo(ByVal plngShort as Long)

is equivalent to saying

Function Foo(plngShort as Long)

Dim lngMyShort as Long
lngMyShort = plngShort

I've never explicitly tested that memory/speed theory, but it sounds
reasonable to me--why tax the user when you can just write better code
instead? Of course, I work (systematically) alone, so maybe that's my
real problem...

Nov 13 '05 #34

P: n/a
Steve Jorgensen wrote:
However, in some cases, you actually need to get two or more
variables back, and in that case, a function would not work (unless
you did something like returning a string with multiple delimited
return values, and then parsed those out -- ick!), and a subroutine
with multiple ByRef parameters is just the ticket.

Sometimes (not always), this is a sign that a class, or in some cases, a user
defined type would be helpful.


You can also pass an array as a parameter, but then you can also return
an array as the function, e.g. Function ReturnArray(params) as String()
However, it is helpful for peace of mind when to see the ByVal and know there
can be no side effects, no matter what the code does. This also clarifies
that the procedure has no -intended- side effects on the parameter.


ByRef is better performance wise :-)

--
[OO=00=OO]
Nov 13 '05 #35

P: n/a
rkc
Mike MacSween wrote:
Thanks Rick. So those Properties. Is a 'Property' of a class in Access
equivalent to a Public method accessing a private variable in other OOP
languages?


Exactly. The Property statements are just VB's way of allowing
read/write access using the same procedure name.

Think of a dao.recordset object. Findfirst is a method of the
recordset object that allows you to search for a record. It
doesn't actually return any information. If a find is successful
it sets the .nomatch property to false and the .bookmark property to
point to the found record. Same deal with the simple class built from
your code. You call the function you wrote which in turn sets values of
the result,template and query properties.

Nov 13 '05 #36

P: n/a
Trevor Best <no****@besty.org.uk> wrote in
news:42**********************@news.zen.co.uk:
Steve Jorgensen wrote:
However, in some cases, you actually need to get two or more
variables back, and in that case, a function would not work
(unless you did something like returning a string with multiple
delimited return values, and then parsed those out -- ick!), and
a subroutine with multiple ByRef parameters is just the ticket.

Sometimes (not always), this is a sign that a class, or in some
cases, a user defined type would be helpful.


You can also pass an array as a parameter, but then you can also
return an array as the function, e.g. Function ReturnArray(params)
as String()


Well, an array is going to be appropriate if you need pairs or
groups of values, and you need an undeterimined number of them.
However, it is helpful for peace of mind when to see the ByVal
and know there can be no side effects, no matter what the code
does. This also clarifies that the procedure has no -intended-
side effects on the parameter.


ByRef is better performance wise :-)


I don't think I'd contemplate returning an array. Something about
that just seems wrong.

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

P: n/a
I had a search for various OOP and Access things. This was one of the more
useful posts:

http://groups.google.co.uk/group/com...bff115c3?hl=en

You appear to have used classes a lot in Access. Have you found integrating
an OOP approach in an only semi OOP environment (apparently) useful? More
useful in certain types of projects than others?

I'm still not sure that I would/will use a class for the example I started
this thread with. Part 2, section 1 of the posters long post might apply
here:

"1- Classes are used to model data not functionality. It just happens
we need functions to manipulate data. This is a bit subtle, but when
programming in OO we shift our focus from functions (which happens to
need data) to objects (which happens to need functions).

I know this is only an example but people not familiar with OO could
get the wrong idea. It seems some of you are using classes just to
organize code or get similar/related things _together_. Classes are
not a panaceia to handle any programming problem... Let's be more
carefull about applying classes, please... Let's focus on data (with
functions)."

But I'm not sure. Maybe clsMailMerge is a 'thing' not a 'do'.

Cheers, Mike
Nov 13 '05 #38

P: n/a
rkc
Mike MacSween wrote:
You appear to have used classes a lot in Access. Have you found integratingan OOP approach in an only semi OOP environment (apparently) useful? More
useful in certain types of projects than others?
Don't mistake the use of my own objects in Access as an OOP approach.
I sure don't. I've never found a need to write an interface and try
my hand at polymorphism in anything I've been paid for.

Everything in Access is an object. Many of the objects are built using
other objects. A recordset object maintains a collection of field
objects. A field object maintains a collection of property objects.
You don't have to know anything about inheritance or polymorphism to
use the objects Access provides.

I simply follow that lead.
"1- Classes are used to model data not functionality. It just happens
we need functions to manipulate data. This is a bit subtle, but when
programming in OO we shift our focus from functions (which happens to
need data) to objects (which happens to need functions).
So according to this fellow the dao.database class is an inappropriate
use of a class. Maybe the point is too subtle for me. Execute,
OpenRecordset, and CreateQueryDef seem like functionality to me.
But I'm not sure. Maybe clsMailMerge is a 'thing' not a 'do'.


Running a mail merge is not an object. The data you have to
collect and the methods that collect that data in order to
run a mail merge certainly could be. The fact that after all
the data collecting is done a method that run's a mail merge
might be part of the object doesn't make the object a 'do'.
The method is a 'do'. Just the way the Execute method is a
'do' as part of the database object. Put all that together and
you have a process. A process is a thing.

Nov 13 '05 #39

P: n/a
rkc <rk*@rochester.yabba.dabba.do.rr.bomb> wrote in
news:Vk******************@twister.nyroc.rr.com:
Mike MacSween wrote (quoting Fernando C Martins):


[]
"1- Classes are used to model data not functionality. It just
happens we need functions to manipulate data. This is a bit
subtle, but when programming in OO we shift our focus from
functions (which happens to need data) to objects (which happens
to need functions).


So according to this fellow the dao.database class is an
inappropriate use of a class. Maybe the point is too subtle for
me. Execute, OpenRecordset, and CreateQueryDef seem like
functionality to me.


You've missed the point of the quoted criticism. In the quoted
example, clAdd had an Add() method. But its parent class wasn't
actually an object, it was just something to hang the method off of.

Execute and so forth are methods that do something based on their
parent object, using the parent object. That's very different from
what was being criticized in the ancient 5-part post on classes.
But I'm not sure. Maybe clsMailMerge is a 'thing' not a 'do'.


Running a mail merge is not an object. The data you have to
collect and the methods that collect that data in order to
run a mail merge certainly could be. The fact that after all
the data collecting is done a method that run's a mail merge
might be part of the object doesn't make the object a 'do'.
The method is a 'do'. Just the way the Execute method is a
'do' as part of the database object. Put all that together and
you have a process. A process is a thing.


For me, the difference in classes versus typical functions and
subroutines is that in a class, you assign values to an object and
then you execute the object's methods. This is completely different
from the thinking in most Access programming.

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

This discussion thread is closed

Replies have been disabled for this discussion.