Page 1 of 1
Passing objects by reference
Posted: Thu Dec 09, 2021 6:23 pm
by OhioJoe
Another of my dumb questions:
I've always been under the impression that objects are passed by reference. Apparently not so.
Code: Select all
CLASS JoeClass INHERIT Something
HIDDEN JoeFile as XUseFile // inherits from DBServer
METHOD JoeMethod CLASS JoeClass
SELF:JoeFile := XUseFile( "JOE.DBF" .. )
WHILE !SELF:JoeFile:Eof
? XGetTheName( SELF:JoeFile )
SELF:JoeFile:Skip(1)
ENDDO
RETURN NIL
FUNCTION XGetTheName( SomeFile AS XUseFile ) AS STRING STRICT
RETURN SomeFile:FIELDGET(#NAME)
Apparently in the example above, the SELF:JoeFile object is copied when passed to XGetTheName() rather than passed by reference as I always assumed was the case. Variants of this occur hundreds of times in our main application so I'm thinking there might be a performance advantage to making the appropriate changes. First a couple of questions:
1. Is it in fact true: the object above is NOT passed by reference ?
2. And if so, how can I change the syntax so that it works in both VO and X# ?
Thanks in advance for your assistance.
Passing objects by reference
Posted: Thu Dec 09, 2021 8:28 pm
by ic2
Hello Joe,
What happens here is that you open another instantiation of that dbServer. If you debug your application in VO and have a breakpoint somewhere, then click on the envelope in the upper left corner and select dbWork areas, you will see something like this
No ALIAS
1023 JOE.DBF
1024 JOE_1.DBF
and more like that with more instantiations.
It also means that you should close your object on finalizing/closing the window or method where you assigned each DBServer object.
Opening a DBF will come with a speed penalty. However, if you would open your DBF once, using something like a GLOBAL JoeFile object (or comparable), you must realize that doing something in 1 method, like a skip, moves the recordpointer in the global object with possible unwanted effects on the other places where you use JoeFile where you probably do not expect changes caused by other pieces of code.
So you may not need/want to change it everywhere but some rather "static" databases could be opened once & centrally, like lookup tables with data like countries, languages etc.
It would/could work the same in VO & X# for what you write as example.
Dick
Passing objects by reference
Posted: Thu Dec 09, 2021 8:39 pm
by robert
Joe,
In the code
You are passing the HIDDEN field JoeFile to the function.
The parameter is declared as
That means that the original value inside SELF:JoeFile is NOT changed when you create a new object of type inside XGetTheName.
However, since the XUseFile is a class, this is a Reference type. That means that SELF:JoeFile contains a reference to the object that is in the Heap of your program.
In the call to XGetTheName you are creating a copy of the reference. That points to the same memory location, like in the image below:
- Reftypes.png (7.71 KiB) Viewed 508 times
The same happens in VO and in X#. You are copying the reference, but both copies point to the same object in memory.
Robert
Passing objects by reference
Posted: Thu Dec 09, 2021 9:03 pm
by Chris
I think there's a bit of confusion between "passed parameter by reference" and "passing a reference of the object", which are different things.
When you use this:
Code: Select all
oMyObject := MyObject{}
SomeFunc(oMyObject)
? oParam:Something // prints 1
FUNCTION SomeFunc(oParam AS MyObject) AS VOID
oParam:Something := 1
CLASS MyObject
EXPORT Something := 0 AS INT
then a reference to the object is passed to the function (you "pass a reference to the object"), and when you change something to this object properties, it is reflected to the original variable passed to it.
But when you do this:
Code: Select all
oMyObject := MyObject{}
oParam:Something := 123
SomeFunc(REF oMyObject) // or "@oMyObject"
? oParam:Something // prints 0 this time, as it's a new object
FUNCTION SomeFunc(oParam REF MyObject) AS VOID
oParam := MyObject{} // create and pass back a completely new object
now you are "passing the parameter by reference". When you do that, then you can completely change the param and assign to it a completely new object, and this new object will be passed back to the code that calls the function.
.