If the code is in the subform's module, Me would be properly referring to the current class object so it should work. But remember, it isn't instantiated as a form in the traditional sense when it is running as a subform.
We have spoken about this before:-
somefunc Me
passes the Form Object but:-
somefunc (Me)
because of the parentheses, attempts to evaluate the Me Object and returns the default which is the Controls Collection and that too is an Object.
Simply don’t put unnecessary parentheses around Objects.
i realised what the cause was, and i forgot i posted this here.
yes - i eventually realised there were three ways of expressing what i wanted
somefunc me
call somefunc(me)
somefunc (me)
the first two pass the form, the last passes the controls collection.
I am used to putting brackets round things, and do it automatically. I just didn't realise the significance of omitting the call keyword, as it "seemed" to work. I know we have had this discussion before with respect to msgbox.
I still do not quite understand the technicalities, but I can see there IS something going on.
I can’t say I fully understand the technicalities either, but here are some clues which might help.
In the case mentioned the space before the opening parenthesis means that the parentheses are not simply enclosing an argument list passed to a Function. Rather, the parentheses are attempting to evaluate that which the parentheses enclose.
If we think mathematically, parentheses mean “evaluate this expression first”. In this case the expression is a Form Object and it appears to get evaluated to its default. The default for a Form is its Controls collection which is also an Object. So the evaluation of the Form Object produced a Controls Object before it was passed.
But a Controls Object is not a Form Object and so a Type Mismatch error was raised between the passed Object (Controls) and the received Object (Form).
The same error did not occur when the passed Object (Controls) was received as a generic Object. A generic receiving Object does not know, or care, what the passed Object is. All a generic receiving Object is, is a place to store a 32 bit pointer to any type of Object and therefore does not have a Type. Since it doesn’t have a Type then no Type Mismatch error can occur.
In other situations, the parentheses “evaluate this expression first” can force a pass by value (ByVal) even if the Procedure receives by reference (ByRef). This is speculation but what I think happens, in this situation, is this. An expression is evaluated and the result of that evaluation is passed ByRef. Any modification of the result of the evaluation, by the called Procedure, may or may not affect the result of the evaluation, I don’t know. But the important thing is that, if it did, then only the result of the evaluation would be affected, not the expression which was evaluated prior to the pass.
All that may seem like gobbledygook so all I can suggest to people is to sit down and try to break things by using unnecessary parentheses in VBA. Eventually I think people may come to the conclusion of:-
>>Chris - i am sure you are right about the brackets, but it's a hard habit to break for me.<<
If that implies you are just going to believe me then please don’t.
I think the fastest way to learn not to do something like this is do the work yourself and see the results.
Code:
Sub TestIt()
Dim X As Long
X = 8
TryThis X
MsgBox X [color=green]' << 5[/color]
X = 8
TryThis (X)
MsgBox X [color=green]' << 8[/color]
End Sub
Sub TryThis(ByRef X As Long)
X = 5
End Sub
Don’t just look at it and simply believe me, try it yourself.
Play with it, try converting it to a string or anything else, and try to break it.
I'm confused. From your example, it looks like
TryThis X
passes by reference. And
TryThis (X)
passes by value.
I also added
Call TryThis(X)
which passes by ref
Then I duplicated the test after changing the sub to be ByVal:
Code:
Sub TestIt2()
Dim X As Long
X = 8
TryThis2 X
MsgBox X ' << 8
X = 8
TryThis2 (X)
MsgBox X ' << 8
X = 8
Call TryThis2(X)
MsgBox X ' << 8
End Sub
Sub TryThis2(ByVal X As Long)
X = 5
End Sub
And in all cases, the original value of X is preserved so the argument is passed ByVal.
The only conflict seems to be:
TryThis (X)
Which passes by value regardless of what the sub says.
Actually sounds like a bug to me.
You said to NOT use "Call name (argument)" and I don't see why since it respects the sub's definition when the method you suggested does not. Did I misunderstand your statement?
my experience with this one, and your explanation that adding the brackets resolved the argument to it's default value is clear enough.
i learned to program in pascal, and brackets are required in pascal - so it seems strange for them to be optional, and maybe even stranger that using/not using them is more than just a matter of taste.
likewise in pascal, parameters are passed byval, by default - and i didn't realise it was the other way round in vb. maybe because of that background, it's very rare indeed that i ever change a parameter within a procedure anyway.
I don’t think I said NOT to use "Call name (argument)" and sorry if something came across that way. What I am saying is not to use unnecessary parentheses because they can affect the result.
The use of the word Call also adds another level of complication in that it modifies the intended use of the parentheses.
Some people use the word Call as a way to help document their code. That is fine but the word Call is not just optional, it can affect the result. People should be aware of the consequences of using/not using the word Call.
When a Sub receives by reference ByRef:-
Sub TryThis2(ByRef X As Long)
TryThis2 (X) forces a pass by value (ByVal) but
Call TryThis2(X) allows the pass (ByRef) because the intension of the parentheses has been modified by the word Call. Note that even the editor knows what’s going on and removes the space.
So there are two different intensions of the parentheses in the above.
The parentheses in Call TryThis2(X) simply enclose the argument list.
The parentheses in TryThis2 (X) forces a pass by value.
We can combine the two intensions of the parentheses like this:-
Call TryThis2((X))
Here the outer parentheses enclose the argument list and the inner parentheses force a pass ByVal.
We can also combine the two intensions of the parentheses like this:-
Code:
Sub TestIt3()
Dim X As Long
Dim Y As Long
X = 8
Y = 8
Call TryThis3((X), Y)
MsgBox X & " " & Y ' << 8 5
End Sub
Sub TryThis3(ByRef X As Long, ByRef Y As Long)
X = 5
Y = 5
End Sub
Here the outer parentheses enclose the argument list and the inner parentheses around X force X to be passed ByVal. But Y is allowed to be passed ByRef because it has no parentheses to force it to be passed ByVal.
So it becomes a misuse of parentheses, unless they are actually required, and the word Call just complicates matters.
With the original problem Dave found I was surprised that a Form Object got evaluated to a Controls Object. I still think it is due to the compliance with the mathematical notion of parentheses in as much as “Evaluate this first”. In this case, first means before the pass to the procedure. What is passed is the result of the evaluation, not the argument itself, and therefore the original argument is not affected.
I don’t think it is a bug, though, but rather a feature which may be useful. It may be useful to leave a receiving procedure in ByRef mode and control the pass mode in the caller. It is certainly possible to have two, or more, callers each controlling the pass mode by the use, or not use, of parentheses around its passed argument(s).
It also means we can not simply look at the Sub header:-
Sub TryThis3(ByRef X As Long, ByRef Y As Long)
and say “Both arguments are being passed ByRef”. To be certain we need to look at both ends of the pass, the caller and the receiver.
In any case we have to be aware of the difference parentheses can make.
The really bizarre thing is the way the number of arguments even makes a difference.
Also remember that arrays are always ByRef regadless of argument declaration.
Also note that the while VBA default is to pass arguments ByRef in VB.NET is it ByVal. Best to always declare the type of arguments and understand when the brackets force an evaluation.
VBA is a strange and beautiful beast but sometimes we have to be aware not to grab it by its tail.
Since it was face to face and in public I will drop a name here. A few years ago, Luke Chung and I had a public discussion about Option Explicit defaulting to Off in VBA.
For many years Luke, and others, have hammered Microsoft to turn Option Explicit On by default. Microsoft has steadfastly refused to do so.
My argument was that, by Option Explicit being Off by default, it allowed people to write some, perhaps silly code… but it usually works.
Luke’s argument was that the reason Option Explicit defaults to Off is that “It stops the phones ringing at Microsoft.”
To me, these two arguments are simply two phases of the same argument and lead to the same result. By allowing ‘Silly code which usually works’ it ‘Stops the phones ringing at Microsoft’. The result is the same; Option Explicit is Off by default.
Consider an architect using AutoCAD. That person is not a silly person but they may want to use VBA. They may write what we would call silly code but it still works. They don’t declare a variable so it becomes a Variant. They can almost throw the kitchen sink at a Variant and it sticks. They don’t have to call Microsoft simply because, most of the time, it works.
I’m not against Option Explicit being On, far from it, but I am against it being On by default. As programmers we may like it turned On by default but VBA was designed for people not just programmers.
So; what has all this got to do with the subject matter of this thread?
Simply put; VBA is a beautiful language, there’s nothing quite like it. At times we can throw the kitchen sink at it and it will stick. However, there are times when that same beautiful beast will bite.
It’s the same beautiful beast; it’s just that this time it was grabbed by its tail.
It’s not the beautiful beast’s problem; it is our problem for not understanding the beautiful beast.
Rather than us having to jump all over the www could you please reproduce the essence of your arguments in code in this thread?
Also, please be aware that even some of the ‘big names’ at UA don’t have a clue when it comes to VBA. I’m not saying they should but they sometimes have the disposition to pretend they do.
Hardly worth the argument when it is so easily set by the user.
(For those who still type Option Explicit every time:
VBA Editor > Tools > Options > Require Variable Declaration)
I agree with MS. Beginners don't need the extra detail of having to declare variables. Those who persist find out quite quickly.
>>Hardly worth the argument when it is so easily set by the user.<<
I, and others, think it is worth the argument because it more clearly explains what VBA is intended to be ’out of the box’. Easy to use for people not just programmers.
That is the reason Option Explicit exits in the first place. If it was turned On by default then who would turn it Off? And if it was never turned Off; why have the option at all?
Will get to it tonight. I will tie it all together.
Also, please be aware that even some of the ‘big names’ at UA don’t have a clue when it comes to VBA. I’m not saying they should but they sometimes have the disposition to pretend they do.
Agree absolutely. And in my expereince they don't like to talk about it.
I am somewhat amused by some contributions to their code archive and wiki.
eg A function to reverse a string? Hello? strReverse() has been in VBA since at least 2003. Moreover the first sample code provided was bewildering complex for such a simple task.
I completely rewrote a function they featured from their home page because the original code was so clumsy. Take a look at the earlier version in the history. My version avoids the trial and error methodoogy and is about thirty percent faster.
I also pointed out to the original author (by personal message) that he coded dangerously. I didn't even get a reply.
Actually the issue with his coding was quite topical in the context of this thread. The code did not declare how the arguments were passed so they defaulted to ByRef. They then proceeded to change the variable inside the function.
I only rewrote the function because I couldn't stand seeing it promoted in its original form but I won't be contributing any more to their wiki. The only edit after mine was to remove any reference to the actual authors in the code just leaving their "Code Courtesy of UA... " and Creative Commons License statements.
I, and others, think it is worth the argument because it more clearly explains what VBA is intended to be ’out of the box’. Easy to use for people not just programmers.
I meant hardly worth the argument with MS for those wanting it on by default.
That is the reason Option Explicit exits in the first place. If it was turned On by default then who would turn it Off? And if it was never turned Off; why have the option at all?