Menu

Delegates

Will Pittenger

Overview

.NET has something that Java currently (as of JDK 7) lacks: Delegates. A delegate is like a C/C++ function pointer. C# and other .NET languages can use them for [Events] and passing references to functions around. ASIL uses the same concept and allows delegates to be used for the same types of activities. The biggest change from .NET's version is that ASIL supports two types of property delegates. .NET has no property delegates at all. ASIL also allows for delegates pointing to complex statements.

List of allowed types

The table below shows what types of callable code that work with delegates:

Callable code type Allowed? Details
Operators
Constructors Constructors are always called implicitly with the new keyword.
Creators These are private and hidden to all code except that generated by the compiler.
Destructors These are private and hidden to all code except the garbage collector.
Commands The syntax must match exactly.
Functions Again, the syntax must match exactly. The return type also has to mach.
Complex Statements Not only does the syntax need to match exactly, but the instructions statement must also match.
Properties First, the type must match—including usage of the const, ref, out, and byvalue keywords. Second, the delegate type must specify if the property should provide a get accessor, set accessor, or both. Listing neither specifies both. Function delegates can match some properties as long as they have a get accessor. Those properties can also match some functions.
Property accessor The delegate type must specify if the delegate is for the set or get accessor. (The property doesn't have to provide the other.) This will NOT match ANY property—only accessors!

Note: Delegates for some commands will match some Property set accessors. Similarly, some function delegates will match some Property get accessors. In both cases, the reverse is also true. This should be allowed and shouldn't be an error condition.

The types involved

The delegate type is an instance of DelegateType which is derived from Type. Instances of a delegate are instances of DelegateInstance with a reference to the DelegateType and are derived from Object. Multiple derivation might be used on both to account for the various allowed types of delegate.

Declaring a delegate type

All types of delegate use the same syntax as the type of callable code they represent, except for complex statements (which get an extra clause) and the delegate keyword (all types). The code below has samples of each declaration. What would be the identifier for the procedure becomes the name of the delegate type. The code also creates a instance of the type. All delegate instances are reference types.

delegate command CommandDelegate var i%
var CommandDelegate MyCommandDelegateReference = null ' The value you're initializing the delegate instance to must either exist already or be null.  You can't declare the procedure here!

delegate function FunctionDelegate
  returns float
var FunctionDelegate MyFunctionDelegateReference = null

delegate statement StatementDelegate var ref String strParam
  instructions String ' This is how you list the instruction list passed to the statement.  Note the list is of types and not variable names.
var StatementDelegate MyStatementDelegateReference = null

delegate property double MainPropertyDelegate
  get
  set
var MainPropertyDelegate MyMainPropertyDelegateReference  = null

delegate property double IndexedPropertyDelegate[int I] ' No accessors given so this requires both
var IndexedPropertyDelegate MyIndexedPropertyDelegateReference = null

delegate property double GetOnlyPropertyDelegate
  get
var GetOnlyPropertyDelegate MyGetOnlyPropertyDelegateRefence = null

delegate property double GetAccessorPropertyDelegate.get ' Note the ".get" part
var GetAccessorPropertyDelegate MyGetAccessorPropertyDelegateReference = null

delegate property double SetAccessorPropertyDelegate.set
var SetAccessorPropertyDelegate MySetAccessorPropertyDelegateReference = null

Obtaining a delegate instance from a procedure name

In current versions of the C# language, the compiler implicitly replaces the name of a function with a delegate instance. ASIL though needs an extra step as it might look like you want to call the function. This is especially important when the procedure is a function or property returning a matching delegate. So ASIL makes use of the & operator like C/C++ did. Below are a series of assignments to the variables we declared in the sample above. (Note: the following code is valid DASIL, but not SASIL as SASIL doesn't allow executable code to live at the same level as procedure declarations.)

command MyComnand var int i ' A variable doesn't need to be declared the same way to match.  So "int i" matches "i%".
  ' Have the command do something
MyCommandDelegateReference = &MyCommand

function MyFunction
    returns float
  ' Have the function do something
MyFunctionDelegateReference = &MyFunction

statement MyStatement var out String strParam
  var S$ = "sdfs"
  instructions S$
MyStatementDelegateReference = &MyStatement

property double MyFullProperty
  get
    return 5.3
  set
    ' store the value somewhere
MyMainPropertyDelegateReference = &MyFullProperty
MyGetAccessorPropertyDelegateReference = &MyFullProperty.get ' Note: the ".get" part cause this to match an accessor **delegate**

property double MyIndexedProperty[int i]
  get
    return someArray[i]
  set 
    ' do something with the passed value
MyIndexedPropertyDelegateReference = &MyIndexedProperty

Samples of delegates that don't look like they should match—but do

As mentioned before, the following types of delegates can match each other:

One type The type that might match
Command <==> Property set accessor
Function <==> Property get accessor (Even though callers can ignore the return value from a function, functions can NOT match property set accessors as those effectively return the ASIL equivalent of void, which functions in ASIL can't return.)
Function taking no parameters <==> Non-indexed property that has a get accessor
Function taking a single parameter that matches its return type <==> Non-indexed property that has both accessors
Function taking parameters <==> Indexed property where the index parameters match the function parameters
Function taking a single parameter that matches its return type plus other parameters <==> Indexed property where the index parameters match the extra function parameters

Below is a sample of code that demonstrates some of these matches. This code also assumes the types declared above and is once more technically DASIL, not SASIL.

command PropMatchCommand var double dbl
  ' Do something here
MySetAccessorPropertyDelegateReference = &PropMatchCommand ' Valid

function PropMatchFunc
    returns double
  return 5.35
MyGetAccessorPropertyDelegateReference = &PropMatchFunc ' Valid

property int CommandMatch
  set
    ' Do something with the value
MyCommandDelegateReference = &CommandMatch.set ' Valid

property float FuncMatch
  get
    return 3.65345
MyFunctionDelegateReference = &FuncMatch.get ' Valid

Calling the procedure referenced by a delegate

Once you have a non-null value inside a delegate reference, calling it is just like calling the actual procedure directly. The trick is making sure the reference is non-null. If you don't, a NullReferenceError (which doesn't need to be declared or caught) might be thrown. So you'd call MyCommandDelegateReference from above like this:

if MyCommandDelegateReference <> null then
  MyCommandDelgateReference 5

Related

Wiki: Events
Wiki: Functions
Wiki: Generics
Wiki: Home
Wiki: Keywords
Wiki: Properties
Wiki: keywords-delegate
Wiki: keywords-event
Wiki: keywords-function
Wiki: keywords-instructions
Wiki: operators-amp