Modify Object by reference
Hello friends,
I tripped over the following problem:
I write a class module named SomeObject to make an object which has two public variables, a long and a string, as properties:
Code:
'the contents of the class module
Public lVar As Long
Public sVar As String
Then I have a sub which modifies a long and a string which are passed by reference
Code:
Private Sub ModifyByRef(ByRef lv As Long, ByRef sv As String)
lv = 10
sv = "gaga"
End Sub
Now for the problem: I declare an object of the above mentioned type, fill some values in and pass the values to the modifying routine, but no modifying takes place.
Code:
Private Sub btnTestObj_Click()
Dim so As New SomeObject
so.lVar = 1
so.sVar = "abcd"
Print so.lVar, so.sVar
ModifyByRef so.lVar, so.sVar
Print so.lVar, so.sVar
End Sub
There is no error. It seems to be ok to pass the objects properties, which in fact are simple public variables, byref to the modifying sub, also as long as within the sub you can verify single stepping that a modification takes place. Nevertheless, when returning, the old values persist.
Why???
Re: Modify Object by reference
Re: Modify Object by reference
Yes. Well, so what? Everything is private within the Form.
Do you think it would work with a public object maybe declared in a module?
I can go and try that.
Re: Modify Object by reference
Well, alas, your explanation, brief as it is, explains nothing.
I have made so a public SomeObject defined in a module and no change takes place when the ModifyByRef is called.
Re: Modify Object by reference
Try +1 in Modify()...
No compiler here...
Re: Modify Object by reference
Hey WoF :wave:
Not sure if this what you want....
I made two properties in the class :
Code:
Option Explicit
'the contents of the class module
Private lVar As Long
Private sVar As String
Public Property Get L_Long() As Variant
L_Long = lVar
End Property
Public Property Let L_Long(ByVal vNewValue As Variant)
lVar = vNewValue
End Property
Public Property Get S_String() As Variant
S_String = sVar
End Property
Public Property Let S_String(ByVal vNewValue As Variant)
sVar = vNewValue
End Property
Then, it is easier to manipulate these values from the form. In the Form, I did this :
Code:
Option Explicit
Dim so As New SomeObject
Private Sub Command1_Click()
'Dim so As New SomeObject
' so.lVar = 1
' so.sVar = "abcd"
so.L_Long = 1
so.S_String = "abcd"
' Print so.lVar, so.sVar
Print so.L_Long, so.S_String
ModifyByRef 10, "LADY gaga is Crazy" 'so.lVar, so.sVar
Print so.L_Long, so.S_String
End Sub
Private Sub ModifyByRef(ByRef lv As Long, ByRef sv As String)
' lv = 10
' sv = "gaga"
so.L_Long = lv
so.S_String = sv
End Sub
That was the only way i get this right. I think I'm not very bright or my brain is frozen this morning :). But, in any case, I hope it helps.
Re: Modify Object by reference
@David: Where a simple assignment fails, an increment would not work either.
Nevertheless I tried. Modification of the variable, although passed by ref, is not possible.
@Hannes: No, you simply swapped the premisses. You are passing the new values as arguments and your modify routine simply puts them to the so properties.
It's the other way round. The so properties must be passed to the modifying routine byref.
Fact is, the ModifyByRef() routine is part of a dll and I cannot change it. It expects two longs and will return some values in them to the VB caller. The dll is not aware of the so object.
I only made this sample as simple as possible to show what I mean.
In the object I use simple publics, because I don't need any procedural support, but also when having written get and let procedures like you did, there is no way I can pass a property to be modified byref to another sub, or so it seems.
Re: Modify Object by reference
Quote:
Originally Posted by
WoF
There is no error. It seems to be ok to pass the objects properties, which in fact are simple public variables, byref to the modifying sub, also as long as within the sub you can verify single stepping that a modification takes place. Nevertheless, when returning, the old values persist.
Why???
Because the VB is able to pass the expression's value by reference. "so.lVar" or 12 or (lVar) are the examples of expression.
Possible solution is
Code:
i=so.lVar: s=so.sVar
ModifyByRef i, s
so.lVar=i: so.sVar=s
Re: Modify Object by reference
Quote:
Originally Posted by
WoF
@Hannes: No, you simply swapped the premisses. You are passing the new values as arguments and your modify routine simply puts them to the so properties.
It's the other way round. The so properties must be passed to the modifying routine byref.
Oh, OK - sorry for misunderstanding :blush:
Quote:
Originally Posted by
Vi2
Possible solution is
Code:
i=so.lVar: s=so.sVar
ModifyByRef i, s
so.lVar=i: so.sVar=s
Yes, that will work.
If you do this WoF :
Code:
Private Sub Command1_Click()
Dim so As New SomeObject
Dim i As Long
Dim s As String
i = 10
s = "abc"
i = so.lVar: s = so.sVar
Print so.lVar, so.sVar
ModifyByRef i, s
so.lVar = i: so.sVar = s
Print so.lVar, so.sVar
End Sub
It will work.
As you had it :
Code:
Dim so As New SomeObject
so.lVar = 10
so.sVar = "abc"
Print so.lVar, so.sVar
ModifyByRef so.lVar, so.sVar
Print so.lVar, so.sVar
Nothing happens! Why, because you keep passing the same values the whole time. so.lvar and so.svar keeps staying the same, ie. 10 and abc. ModifyByRef simply accepts the values ( 10 and abc ), and does nothing. That is how I understand it.
Sorry for the confusion :blush:
Re: Modify Object by reference
No, Hannes. Look, ModiFyByRef() will modify any passed variable of apropriate type.
Code:
Private Sub ModifyByRef(ByRef lv As Long, ByRef sv As String)
lv = 10
sv = "gaga"
End Sub
Before the call so.lvar is 1 and so.svar is "abcd". They should be modified to 10 and "gaga".
Thing is, with a UDT it would work. Keeping the above modify routine as is and using this code everything is as expected:
Code:
Private Type SomeType
lVar as Long
sVar as String
End Type
Private Sub btnTestObj_Click()
Dim so As SomeType
so.lVar = 1
so.sVar = "abcd"
Print so.lVar, so.sVar
ModifyByRef so.lVar, so.sVar
Print so.lVar, so.sVar
End Sub
vi2's proposal (thanks) is completely right, and I have certainly found that out already.
Only it is not really elegant (sorry). Anyway I had to do that because there seems no other way.
Still I'm curious WHY an object's property, even when being a simple public var, cannot be passed byref to a modifying routine. Seems to be strange...
Re: Modify Object by reference
Quote:
Originally Posted by
WoF
Still I'm curious WHY an object's property, even when being a simple public var, cannot be passed byref to a modifying routine. Seems to be strange...
I had a similar problem in .NET and fixed it by making the Variables Private and adding Property's to the class..
Code:
Private IlVar As Long
Private IsVar As String
Public Property Get Lvar() As Long
Lvar = IlVar
End Property
Public Property Let Lvar(ByRef value As Long)
IlVar = value
End Property
Public Property Get sVar() As String
sVar = IsVar
End Property
Public Property Let sVar(ByRef value As String)
IsVar = value
End Property
However trying the same 'trick' in VB6 has no effect..
But.. I've since found out that when VB.NET is compiled it is stripped down to the same process that Hannes posted.. (reported about it here)
This is probably the only way to do it..
Code:
TmpL = so.Lvar
TmpS = so.sVar
Call ModifyByRef(TmpL, TmpS)
so.Lvar = TmpL
so.sVar = TmpS
Re: Modify Object by reference
Yes, I'm afraid it is.
It is absolutely unelegant, but it seems to be the only way.
Well, I did modify my code already accordingly.
Only, I would have liked to know why this IS.
But never mind. If noone has an explanation, why public variables of an object cannot be modified by reference, I just have to take it in and live with the solutions we got. :)
Although it seems quite illogical.
It seems like the mentioned variables are explicitly passed ByVal (although declared ByRef), because they can be modified and used within the ModifyByRef() as you can with any variable passed ByVal.
Re: Modify Object by reference
Quote:
Originally Posted by
WoF
Only, I would have liked to know why this IS.
But never mind. If noone has an explanation, why public variables of an object cannot be modified by reference, I just have to take it in and live with the solutions we got. :)
Although it seems quite illogical.
It seems like the mentioned variables are explicitly passed ByVal (although declared ByRef), because they can be modified and used within the ModifyByRef() as you can with any variable passed ByVal.
There is no public variables for (1) Object variable (SomeObject variable is also Object variable). Instead of public variable VB adds 2 methods: get and let. For example, next parts of code are equivalent:
Code:
Public lVar As Long
Code:
Private m_lVar As Long
Public Property Get lVar() As Long
lVar = m_lVar
End Property
Public Property Let lVar(ByVal src As Long)
m_lVar = src
End Property
VB makes all actions for first case behind the scene, but its behaviour is the same. VB should get the value from get-property (explicit or generated automatically) and pass this value byref into method.
(1) I think that it will be better: There is no public variables inside Object variable.
Re: Modify Object by reference
All that means: YOU CANNOT PASS AN OBJECT'S PROPERTY BYREF TO SOME SUB WHICH WANTS TO MODIFY IT! No matter if it is a public var or a a properly implemented property.
Or am I wrong?
Re: Modify Object by reference
I've been looking up info and thinking about this quite seriously.. and i think i know why...
It might get a little confusing and mixed but try to follow this...
Each Application is allocated to a memory space..
Applications cannot directly modify memory in any other application (including called DLL's). Dont shoot me, You can by finding the Memory location and changing it Indirectly. But there is also the problem of the 64K memory window that cannot be crossed.
Each class object can considered a separate DLL object, as it is the base object of a DLL..
In a class All outside(Public) references are passed ByVal, incase it is accessed across the 64K memory window (Please forgive my terminology)..
And if you followed all that ... By design a Public Class object will not use the Memory pointer's but rather pass the Value, So as not to have Memory Calling issues...
Hope it makes sense.. And if some one can rewrite that better ... PLEASE DO...
Re: Modify Object by reference
mmmmmmm..... I think some thing was over looked here....
There is a difference in class fields, vs class properties...
Class fields:
Code:
Public Class Test
Public SomeName as String
Public Age as Integer
End Class
Are treated as value types....
While a property:
Code:
Public Class Test
Public Property SomeName as String
Public Property Age as Integer
End Class
(yes, I realized I use the VB10 syntax there, sue me, point still applies)
Get treated as reference types and are part of the object.
The difference in this distinction causes the rules to change when they are passed around. And has a lot to do with where they get stored (heap vs stack).
Gremlins - I don't buy that (at least no with out references (no pun intended)) ... granted it's been sometime since i've been out of th VB6 game... but if memory serves (and it could be faulty, I will grant that) ... that's NOT the experience I remember and I did a LOT of work with system that was heavy on the DLLs.
WOF - you SHOULD be able to pass an object's property by ref to be modified... but it has to be a PROPERTY... not a field... they are not interchangeable... in your first post, you show them as fields... not properties.
-tg
Re: Modify Object by reference
Quote:
Originally Posted by
TechGnome
you SHOULD be able to pass an object's property by ref to be modified... but it has to be a PROPERTY... not a field... they are not interchangeable... in your first post, you show them as fields... not properties.
-tg
Do you have VB6 installed ???
Try it...
It will not change a byref property, no matter how you try...
I'll look for a few online references, problem is that anything VB6 is not so easy to find anymore...
Re: Modify Object by reference
Right, Gremlin. A property canNOT be modified byref, neither if it was declared a public field, nor a property get/let pair.
Alas, a thing like "Public Property Somename as String" does not exist in VB6, TechGnome.
I mean, I would have expected that a property, being actually a pair of routines to receive or give back a value, cannot be modified byref, being no actual memory location.
But a public field should be, or so I had expected.
I think this is because of the policy, or better: the way how value passing in VB6 objects is done at all. If you have a get/let pair, it is obvious that there is no actual memory location for that property, because it might even be assembled or computed within the get routine. So the result is stored somewhere in a temporary field. That is like a ByVal parameter passed to a function.
So I think the interface is always doing this. It creates a temporary field where it puts the result of the property-get. In case there is only a public variable it results in putting the contents of this var into the accessible temp field. The user will find n0 difference in using the resulting value, but it NEVER ever allows byref modification.