Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Westi on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Trouble calling class module Subs

Status
Not open for further replies.

JTBorton

Technical User
Jun 9, 2008
345
DE
I have a class module that manages an array for me, and every so often I would like to resize the array. Sometimes I want to preserve the array, sometimes I just want to wipe it clean. I am having trouble making the call. The first line of code is the call, the second is the Sub as it is in the class module. I am recieving the following error:

Compile error:
Expected Function or variable


Code:
List.ReSize_List(Count) = False

Code:
Public Sub ReSize_List(UpperBound As Integer, Optional blnPreserve As Boolean = True)
    If UpperBound > 0 Then
        If blnPreserve = True Then
            ReDim Preserve List(UpperBound)
        Else
            ReDim List(UpperBound)
        End If
    End If
End Sub

I really dont like the syntax VB is forcing me to use for the call. I want to be able to make the call like this:
Code:
[COLOR=green]'To wipe the list clean[/color]
List.ReSize_List(UpperBound:=Count, blnPreserve:=False)

[COLOR=green]'To resize but preserve data[/color]
List.ReSize_List(UpperBound:=Count, blnPreserve:=False)

Any suggestions?

-JTBorton
Another Day, Another Disaster
 
Call List.ReSize_List(Count, False)

Hope This Helps, PH.
FAQ219-2884
FAQ181-2886
 
The problem could be caused by duplicate name List:
- in 'List.ReSize_List..' - guess that it is an instance name of your class,
- in the class 'ReDim Preserve List(UpperBound)' you use a name of the array.

combo
 
PHV Ok that worked. Out of curiosity, why does it matter if you put 'Call' in front of it? Why will it not accept the simple format of List.ReSize_List(Count, False)? When I call other subs in the module (which coincidently only have pass one variable) I can simply use List.[Method] (Variable)

combo I see what you're saying, but that doesn't seem to be a problem. The first List is the name of the class module, the second is a private defined variable type within the class module. It seems to work fine with all the other functions and subs.

-JTBorton
Another Day, Another Disaster
 



or...

List.ReSize_List Count, False


Skip,

[glasses]Just traded in my old subtlety...
for a NUANCE![tongue]
 
Parentheses! They seem to cause no end of confusion.

The syntax is either:
[blue][tt] Call List.ReSize_List(UpperBound:=Count, blnPreserve:=False)[/tt][/blue]
or:
[blue][tt] List.ReSize_List UpperBound:=Count, blnPreserve:=False[/tt][/blue]

But ... parentheses also act to force precedence, so:
[blue][tt] List.[Method] (Variable)[/tt][/blue]
is the second format syntax (i.e. without "Call") and the single parameter is evaluated before making the call. Much of the time this makes no difference, but if the Variable parameter is an object with a default method it can be significant.

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
List.[Method] (Variable)
Tony, another side effect is to pass Variable ByVal.
 
>is to pass Variable ByVal

Actually, it is subtly different from passing ByVal, although for most VBA programmers the effect would appear to be the same.

The evaluation enforced by the parenthesis causes new storage to be allocated to hold the result, essentially an invisible (to VBA) variable. This invisible variable is then correctly passed ByRef or ByVal, as per the definition of the sub or function call.
 
... for most VBA programmers the effect would appear to be the same.

Is there a real difference (documented anywhere) that could in any way be leveraged? Or are you just (correctly) describing conceptually what happens?

Could an optimising compiler not make the two exactly the same? And even if one doesn't at the moment, might not a future version do so, such that whatever differences there might be, could not be relied upon?

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Now forgive me guys if I'm not on the same level of understanding here, but I dont want very much to learn. What do you mean when you say
Tony, another side effect is to pass Variable ByVal.

What other side effect is it? I'm a little confused.

-JTBorton
Another Day, Another Disaster
 
There are two ways to pass a parameter to a subroutine: ByRef, and ByVal. When you pass it ByRef (by reference) you are passing the actual variable in your calling routine, so, if you had a subroutine like this:
Code:
[blue]Sub MySub([red]ByRef[/red] MyVal As Long)
    MyVal = MyVal ^ 2
End Sub[/blue]
and you call it like this:
Code:
[blue]Dim MyLong As long
    MyLong = 10
    MySub MyLong
    MsgBox MyLong[/blue]
you will see the result: 100. The subroutine has changed the actual value of your variable.

But if you pass ByVal (by value) you are passing the Value only (in a copy of the variable, supplied by VBA), so if you had a subroutine like this:
Code:
[blue]Sub MySub([red]ByVal[/red] MyVal As Long)
    MyVal = MyVal ^ 2
End Sub[/blue]
and you call it like this:
Code:
[blue]Dim MyLong As long
    MyLong = 10
    MySub MyLong
    MsgBox MyLong[/blue]
you will see the result, this time: 10. The subroutine has changed the value of the variable it received but this was just a copy of your main variable, and it was discarded at the end of the subroutine, so your variable retains its original value.


Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Sorry, pressed Submit instead of Edit ... to continue ...

You see in the example that the way to tell whether a variable is passed by reference or by value is normally by stating it on the subroutine definition.

A value passed by reference, however, can only affect an actual variable in your main routine if it is a variable. If it is an expression it is transient by definition and already in VBA-owned memory and then, however the subroutine defines it, it will be discarded at the end of the statement.

So, with the first subroutine:
Code:
[blue]Sub MySub([red]ByRef[/red] MyVal As Long)
    MyVal = MyVal ^ 2
End Sub[/blue]
if you call it like this:
Code:
[blue]Dim MyLong As long
    MyLong = 10
    MySub (MyLong)
    MsgBox MyLong[/blue]
you will see the result: 10. (MyLong) is not your variable; it is an expressiion derived from your variable. The expression, stored somewhere by VBA, is indeed changed but you never get to see the result of it.

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Oops, my previous statement
but I dont want very much to learn
was supposed to read I DO want very much to learn. Looks like my brain is on vacation and my fingers are working overtime.

TonyJollans - Thanks for the reply, but perhaps I was not too clear. I understand the concept of Byval and ByRef, and I use them a lot. What I don't understand is the meaning of PHV's statement of how it changes a class module sub call. Why would it affect the syntax of the call? Or maybe I am misunderstanding what PHV was saying.

-JTBorton
Another Day, Another Disaster
 
Tony said:
When you pass it ByRef (by reference) you are passing the actual variable in your calling routine
Are you really? Are you not passing a pointer to it? Is that not what is meant ByRef? Does not the result of the processing pass the new value back to the variable? Not only that, but it passes the new value immediately?

I thought that ByRef meant: THERE...do the following actions to THAT thing. Pointing to THAT, which changes its value according to the instructions.

As opposed to ByVal, which means: do the following actions to THIS value, without changing the thing the original (ByVal) value came from.

For others reading this, it may be important to note that VBA assumes ByRef by default.
Code:
Sub MySub([b]ByRef[/b] MyString As String)
    MyString = "Yippeee!"
End Sub

Sub Whatever()
Dim MyString As String
    MyString = "Yadda"
    MySub MyString
    MsgBox MyString
End Sub
Messagebox result: "Yipeee!" The instructions were done and the value pointed back.

Code:
Sub MySub([b]ByVal[/b] MyString As String)
    MyString = "Yippeee!"
End Sub

Sub Whatever()
Dim MyString As String
    MyString = "Yadda"
    MySub MyString
    MsgBox MyString
End Sub
Messagebox result: "Yadda" The instructions were done - as you can see stepping through MySub (the string DOES change to "Yipeee!" - but the result were NOT pointed back.

Going back to the mention of VBA passing back a ByRef value immediately, if you step through the first example, if you check the value of MyString in the Sub Whatever AFTER:

MyString = "Yippeee!"

in the Sub MySub, but BEFORE the End Sub, MyString is already changed.

Code:
Sub MySub(MyString As String)
[b][COLOR=red]'  NOT defined as ByRef or ByVal[/color red][/b]
    MyString = "Yippeee!"
End Sub

Sub Whatever()
Dim MyString As String
    MyString = "Yadda"
    MySub MyString
    MsgBox MyString
End Sub
Messagebox result: "Yipeee!" The instructions were done and the value pointed back. Again, to those not fully familiar with this stuff, VBA assumes it is ByRef, unless otherwise explicitly declared as ByVal.

Now...here is where I show MY ignorance.
Tony said:
A value passed by reference, however, can only affect an actual variable in your main routine if it is a variable. If it is an expression it is transient by definition and already in VBA-owned memory and then, however the subroutine defines it, it will be discarded at the end of the statement.
How do you pass an expression (but not as a variable representing an expression) to a procedure?

Further, in one of your posts, you say: "(MyLong) is not your variable; it is an expressiion derived from your variable."

This in reference to: MySub (MyLong)

You also state: "The expression, stored somewhere by VBA, is indeed changed but you never get to see the result of it. "

However, stepping through, (MyLong) does NOT change. In the given example, it seems to me that it IS the variable. I think you meant MyVal in the othe rprocedure.

As for never get to see the result, this is incorrect. Stepping through, you can indeed see the result of the change, even though yes, it is destroyed by the End Sub.

It is that "invisible" storage that strongm mentioned. It is this could possibly be used for the "leverage" you mention. You could send the "temporary" value out to another procedure before the termination of the procedure that is holding the "invisible" variable. Say...
Code:
Sub MyTonySub(ByVal MyVal As Long)
    MyVal = MyVal ^ 2
    UsingTempValue MyVal
End Sub

Sub MyTonyLong()
Dim MyLong As Long
    MyLong = 10
    MyTonySub (MyLong)
    MsgBox MyLong
End Sub

Sub UsingTempValue(myInput As Long)
   MsgBox "Here is the invisible value of MyVal.  " & _
      myInput
End Sub
So yes, MyLong remains at 10 (send as ByVal), but you can redirect the value of MyLong ^ 2 (100) someplace else, before that value is gone. I do not know if that could be real leverage, but you certainly can use the value in the new storage that strongm mentions.

Gerry
 
Gerry said:
Are you really? Are you not passing a pointer to it?
Well, yes. And when you call ByVal you are passing a pointer to a copy of your variable, but that is academic.

Almost all machine instructions use addresses to reference operands. On IBM mainframes there are a handful of instructions that use an actual value stored within the instruction; I don't know enough about PC Assembler to say whether it may have similar instructions but, whatever, they are a minority; almost all references are by pointer. That's just the way computers work; I suppose they don't have to work that way, they just do.

All of that is what happens behind the scenes, and is of no consequence to the average user. When you pass ByRef it is as if you pass the actual variable, in that all actions performed in the subroutine act upon that variable. It isn't important what the mechanism at the machine code level is.

I'm sure my description isn't perfect but the full detail would be too much information for most people. Just for the record, when you use an expression as a parameter (as in the original post), an area (or possibly more than one area depending on the type of the result) of storage is set aside for the result of that expression, and it is computed and placed in that area. If you are passing ByRef, the address of that area is placed on the stack; if you are passing ByVal (and this is what strongm was referring to), the contents of that area are copied to another area and the address of that second area is placed on the stack. The subroutine pulls the address off the stack and uses the area pointed to for all actions on that argument. The subroutine does not know, or care, what has happened in the calling routine, or what that area of storage is, or whether it's going to be used again; all it cares about is that it is of the right type and that it can use it.

Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
The reason I was asking was a thread about an Out of Stack message someone was getting, and from looking at their code I could not really see why.

Ah well, 'tis really rather pedantic anyway.

However, I still do not understand HOW you can use an actual expression as a parameter. I mean:

Sub Yadda(10*2, strIn As String)

is going to fail. I can see how you can use a variable that represents an expression. What am I missing?

Gerry
 
No, no! The other way round:

Code:
[blue]Sub Yadda(numIn as long, strIn as String)
    ...[/blue]

then call it with an expression, e.g.

Code:
[blue]Yadda 10 * 2, "text"[/blue]

or

Code:
[blue]Yadda 10, (Selection)[/blue]

Out of Stack space can be caused by recursive calls gone mad. Or, I suppose, theoretically, just by a calling a few levels deep with several parameters, on a machine that's short of memory. Or, well, anything, it's really just a particular way of running oiut of memory.


Enjoy,
Tony

------------------------------------------------------------------------------------
We want to help you; help us to do it by reading this: Before you ask a question.

I'm working (slowly) on my own website
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top