A post in the REAL Software forums asked if REALbasic has a CallByName function like VB has. After reviewing my answer and the CallByName function in VB, I am presenting a more thorough solution here.
First, REALbasic does not have CallByName. However, it does have Introspection (aka reflection) which can be used to achieve this.
The official function definition in VB is:
CallByName(object As Object, procname As String, calltype As Integer, [args() As Variant])
This is a bit limited as it cannot handle return values. I’d also prefer a more object-oriented syntax. So our REALbasic definitions are:
Object.CallByName(name As String, nameType As CallType, ParamArray args As Variant) Object.CallByName(name As String, nameType As CallType, ParamArray args As Variant) As Variant
In order for this to be usable on any object, we’ll implement these as extension methods. First we need to create a module to contain our methods. Create a module called CallByNameExtension. This self-contained module will eventually have everything we need to use CallByName in our projects.
Next, we need to create the CallType enumeration. This is used to specify the type of the we want to call. Our options are Method, PropertyGet and PropertySet. On our module, create a CallType enumeration with those three values (Method, PropertyGet, PropertySet).
Now create our two method signatures for CallByName:
Sub CallByName(Extends obj As Object, name As String, nameType As CallType, ParamArray args As Variant) End Sub
Function CallByName(Extends obj As Object, name As String, nameType As CallType, ParamArray args As Variant) As Variant End Function
Since both of these methods will actually use very similar code, we will create a private worker method to actually do the call. Create a new private method:
Private Function CallByNameWorker(obj As Object, name As String, nameType As CallType, args() As Variant) As Variant End Function
Note that we’ve changed the ParamArray to just a simple array. This is because we cannot resend the parameters as a ParamArray.
Let’s add the simple code to the public methods:
Sub CallByName(Extends obj As Object, name As String, nameType As CallType, ParamArray args As Variant) Call CallByNameWorker(obj, name, nameType, args) End Sub
Function CallByName(Extends obj As Object, name As String, nameType As CallType, ParamArray args As Variant) As Variant Return CallByNameWorker(obj, name, nameType, args) End Function
As you can see, this code simply calls the worker, saving the return value if appropriate. Since ParamArrays are converted to real arrays, we can just pass that along to the worker as well.
In the worker method we’ll use Introspection to actually call the method or to get/set the value of the property. Here is the code:
Private Function CallByNameWorker(obj As Object, name As String, nameType As CallType, args() As Variant) As Variant If obj <> Nil Then Dim info As Introspection.TypeInfo info = Introspection.GetType(obj) Select Case nameType Case CallType.Method // Get the names of all the methods on the object Dim methods() As Introspection.MethodInfo methods = info.GetMethods // Search for the specified method For Each m As Introspection.MethodInfo In methods If m.Name = name Then // We found it, so call it Dim rv As Variant rv = m.Invoke(obj, args) Return rv End If Next Case CallType.PropertyGet // Get the names of all the properties on the object Dim props() as Introspection.PropertyInfo props = info.GetProperties // Search for the specified property For Each p As Introspection.PropertyInfo In props If p.Name = name Then // We found it, so return its value Dim value As Variant value = p.Value(obj) Return value End If Next Case CallType.PropertySet // Get the names of all the properties on the object Dim props() as Introspection.PropertyInfo props = info.GetProperties // Search for the specified property For Each p As Introspection.PropertyInfo In props If p.Name = name Then // We found it so set its value to the first argument p.Value(obj) = args(0) End If Next End Select End If Exception e As RuntimeException Dim eInfo As Introspection.TypeInfo eInfo = Introspection.GetType(e) Dim eMessage As String eMessage = "A " + eInfo.FullName + " occurred." If e.Message <> "" Then eMessage = eMessage + EndOfLine + "Message: " + e.Message End If MsgBox(eMessage) End Function
This code has one significant limitation when it comes to calling methods: it cannot handle overloaded methods. If you have multiple methods with the same name, but with different parameters, then this code will not always call the method you expect. In order to fix this we would have to compare the types of each of the supplied arguments with the types of the arguments for each matching method and then call the one where everything matches. This is all possible using Introspection, but I’ll leave it as an exercise for the reader.
Download the project with all the code: CallByName.rbp.zip

This is really an excellent function. Thanks for the contribution!