Delegates

The Xojo docs about delegates are quite sparse about what you can or cannot do with them and whether they can or cannot take certain kinds of parameters. What they do say is that

A Delegate data type is an object representing a specific method. It is a function pointer with a method signature.

I was recently asked if a delegate that did not make use of any external dynamic library could take an object parameter. The delegate definition and the code creating the delegate are all inside a single Xojo project.

Delegates are kind of esoteric but like many things, when you need one you need one and it may be the only way to do what it is you want to do.

Inside a single Xojo project “delegation” can be done in several ways. Before Delegates what you might often find that an interface would be used. This would work for code all in the same project, but could lead to a lot of interfaces with one method just to be able to declare the delegate. When you use a delegate definition and AddressOf to create the delegate the difference is negligible. In both cases you define a new type, either the interface or the delegate, and then in some way have to implement that type so you can make use of it.

One key difference is that with an interface you can’t just use it with any method that has the proper signature. It has to be implemented by a class and then you need an instance of that class. So there can be more work with an interface in this case.

But notice I wrote that both a Delegate and and Interface define a new data type. What that means is that you can use the delegate name in a DIM statement just like you would use Integer, String, Color, Text etc.

dim delegateReference as MydelegateType

And then you can assign values to it – but in the case of a delegate you need to make sure you assign values that match the signature the delegate was defined with. This is the same as if you declare a variable as an integer you can’t assign a string to it.

For instance if we had the following :

Delegate NoParamDelegate() 
Delegate OneIntParamDelegate(i as integer)

Sub NoParamMethod()
End Sub
Sub OneParamMethod(i as integer)
End Sub
Sub InvalidOneParmMethod(s as string)
End Sub

dim noParam as NoParamDelegate
dim oneParam as OneIntParamDelegate

We have two delegates defined – the NoParamDelegate and OneIntParamDelegate. One takes no parameters. The other takes one integer parameter.

What that means is that the NoParamDelegate can ONLY be assigned to contain the AddressOf a method that takes NO parameters. It cannot hold ANY other pointer to any other method. Given the previous definitions :

// would compile
noParam = AddressOf NoParamMethod
oneParam = AddressOf OneIntParamMethod

// will not compile - you get a type mimatch
noParam = AddressOf OneIntParamMethod
oneParam = AddressOf NoParamMethod

// will not compile 
// although this method has one param the parms do not match types
noParam = AddressOf InvalidOneParmMethod
oneParam = AddressOf InvalidOneParmMethod

Delegates are “fussy” – you MUST assign the addressof a method that has the EXACT SAME SIGNATURE the delegate was defined with.

But once you do this you CAN pass whatever data types you want within your own project.

If you happen to use a delegate to call EXTERNAL code, which is sometimes done in the case of interfacing with system libraries and other non-Xojo code, you often use a Ptr although you can use a delegate as well if you make sure you define the delegate with the signature that matches the external codes (this can be tricky sometimes)

If you do match up the types one thing you will run into is that Xojo objects can not be passed to external code this way. You can only pass ptr’s, structures – careful here as you need to know the specific calling conventions in use – and other simple types. Xojo will coerce many things to the correct type for you just as it does for declares.