Delegate
Delegates are a new UnrealScript concept in UT2003 and beyond. They are (more or less) placeholders for functions. They are particularly used in GUI components: for example, a delegate for the clicking action can be assigned to a specific function without having to re-script the class.
Delegate Syntax
Delegates are declared just like functions, with the small difference, that usually they don't have a function body.
<delegate modifiers> delegate <return type> <delegate name> (<parameter modifier> <type> <parameter name>, ...);
- <delegate modifiers>
- Keywords that specify aspects of the delegate's overall nature and behaviour. These modifiers only affect the delegate itself. When you assign another function to the delegate that functions modifiers will replace the delegate's original modifiers. See Function Syntax for a list of possible modifiers.
- <return type>
- The variable type the function returns. You can't return static arrays due to the way they have to be declared. However, you can use an out variable in this case.
- <delegate name>
- The name of the delegate, chosen by the coder. For advice on naming conventions see Coding Guidelines.
- <parameter modifier>
- Changes the nature of individual parameters. See Function Syntax for a list of possible parameter modifiers.
- <type>
- The variable type of each parameter.
Examples:
delegate bool MyDelegate(bool FirstParam , out int SecondParam, optional string ThirdParam); simulated delegate MyDelegateWithCode() { log("My delegate with code was executed."); }
This second example might be useful if you want a delegate with default code which should be executed clientside. The simulated keyword only applies to the delegate itself. It will have no effect if the function you assign to the delegate is not simulated.
Calling Delegates
Delegates are called like regular functions:
local bool bReturn, bHaveIt; local int Number; MyDelegate(True, 34, "Hello World!"); // parameters passed as literals MyDelegate(bHaveIt, Number); // parameters passed as variables bReturn = MyDelegate(False, Number, "Hi there!"); // save delegate's return value in another variable
When a delegate is called without having a function assigned to it, the delegate's default function body will be used. If the delegate doesn't have a function body, nothing will happen.
Note: If a function of an object that no longer exists is assigned to a delegate, calling this delegate will result in a crash.
Daid303: Does that crash also happens when the function is in actor?
Wormbo: I don't know. That's info from the UDN page about delegates.
Evolution: Yes this would cause a crash regardless of where the delegate is declared. The compiler is supposed to catch all types of delegate assignment which might result in a delegate's associated function not actually existing, but this doesn't work 100% in UT2003. 99% of these compiler bugs are found with delegate assignments from subobject blocks in defaultproperties, so if you're experiencing a crash indicating the 'function blah couldn't be found' try moving your delegate assignment out of defaultproperties into the first function that will be called on your class (InitComponent(), for instance in the GUI). The other way this can happen is if the function you're assigning to the delegate exists in another package. If the function is removed from the other package, and the package is recompiled, but the code containing the delegate assignment *isn't* recompiled, then you'll get also get this crash.
Delegate Assignment
To assign a function to a delegate property simply use the syntax:
DelegateName = FunctionName;
(This also works in a class's default properties.)
You can only assign functions to a delegate that have the same return type and the same number and type of parameters. Optional delegate parameters have to be optional for the function as well. Other parameter modifiers such as out don't have to match. Those modifiers will be replaced by the corresponding modifiers of the function assigned to the delegate.
To restore the delegate's default behavior simply assign None to it. You will have to do that if the function assigned to the delegate belongs to an object you want to be garbage-collected, because for non-actor objects delegates count as references to the object just like a direct object reference.
If an actor has a function assigned to a delegate and the actor is destroyed, the delegate is automatically set to None, just like a direct Actor reference.
Delegate testing
Is is possible to examine what a delegate is set to and test it?
Discussion
Tarquin: If I understand the UDN example correctly, a delegate is a sort of placeholder in a class. When you have an object of that class, you can stick any function you like in the placeholder.
Wormbo: Think of it as a variable that holds a reference to an object of type "function". You can assign objects to it and use them (i.e. execute the function). You can even give it a default value, i.e. a default function body, default function modifiers and default parameter modifiers. Like variables of type Class or arrays where you can further specify the type of class or array you can specify details about the functions that can be assigned to a delegate property.
Foxpaw: I don't suppose there's any way to use delegates in structs, or make arrays of delegates? If there was, you could make a nifty adaptive timeslicing scheme that would keep your framerate high no matter what. (well, okay, not no matter what, but no matter what was in your script)
dataangel: Unfortunately you can't just imagine delegates as being variables that hold references to function objects because as far as I know ucc will give you compile errors whenever you try to use a delegate as a function parameter. Perhaps this is a bug? It'd be really useful to be able to pass functions or delegates as parameters.
Xian: If you can't quit picture Wormbo's description, I think you could rather imagine it as virtually moving a function body in another class without actually modifying it or subclassing it...