Tips & Tricks - ByRef object passing

Primary tabs

Today, I was reading some source code, and encountered the following method signature:

Method SendRequestSync(pRequest As %Library.Persistent, ByRef pResponse As %Library.Persistent)

And I immediately thought, why is there a ByRef?

Beforehand, I was under a (correct) assumption that objects are always passed by a reference, without exception. So, what does ByRef does here? A quick search in documentation yielded information on ByRef  for non-object variables , but it was not what I was searching for.

Turns out that you can pass a reference by reference therefore allowing reference modification in a called code. To clarify, consider this example:

Class Utils.ObjByRef [ Abstract ]
{

/// Do ##class(Utils.ObjByRef).Test()
ClassMethod Test(UseByRef As %Boolean = {$$$YES})
{
    Set Obj = {}
    Set Obj.Property = 1
    Write "At the begining ",Obj.Property,!
    Do ..RefMethod(Obj)
    Write "After Value pass ",Obj.Property,!
    Do ..RefMethod(.Obj)
    Write "After ByRef pass ",Obj.Property,!
}

ClassMethod RefMethod(ByRef Obj)
{
    Set Obj = {}
    Set Obj.Property = 500
}

}

It produces the following output:

>Do ##class(Utils.ObjByRef).Test()
At the begining 1
After Value pass 1
After ByRef pass 500

In the first case we pass object reference by value, so if the called code changes the reference,  the caller doesn't know about it. In the second case the reference is also passed by reference, so if the called code modifies the reference, the caller would get a new reference.

Do you use this feature? How?

Comments

Interesting, Eduard. And do you use this feature anyhow?

I use ByRef a lot, but mostly to indicate that an array or object will be changed in the method. 

In fact, until now, I thought it was necessary to use ByRef in order to "continue the changes to the object back to the calling code".  However, after playing around with some code, including your example, I see that it's not necessary at all, which makes me think that it's useful as an "annotation", so that the programmer knows that the object WILL BE changed. 

Now, I feel that the real "pass by reference" is the dot in front of the variable, and the ByRef is merely an indicator that this variable could be changed when returned.

Is this true?  I'm not really sure what "passing a reference by reference" would produce. I came upon this article because I want several methods in a row to update a log file, which I sometimes add to the method signature as ByRef, and sometimes I don't, and I wanted to know why it still worked (i.e. my log file is created, and is updated in the calling method).

Here is your original example, but without the ByRef:

ClassMethod Test(UseByRef As %Boolean = {$$$YES})
{
    Set Obj = {}
    Set Obj.Property = 1
    Write "At the begining ",Obj.Property,!
    Do ..RefMethod(Obj)
    Write "After Value pass ",Obj.Property,!
    Do ..RefMethod(.Obj)  // pass by reference because I want the object to change
    Write "After ByRef pass ",Obj.Property,!
}

/// notice there's no ByRef in the method signature

ClassMethod RefMethod(Obj)
{
    Set Obj = {}
    Set Obj.Property = 500
}

USER>Do ##class(Utils.ObjByRef).Test()


At the begining 1
After Value pass 1
After ByRef pass 500

ByRef is just flavor text, only passing by dot matters.

Passing an object via dot to ByRef method argument means your code can return other object. If you only modify an existing object you don't need to use ByRef or pass object via dot.

I recommend using ByRef only in cases where you need to return different object.