Functions as Delegates

Scott Waldron Updated by Scott Waldron

As outlined above, functions are often passed to other functions, either within Dino itself or back to the host language, as callbacks. Because Dino is a dynamically-typed language, the host language sometimes needs a little guidance about the signature of the Dino function.

What does “dynamically-typed” mean? Well, in simplest terms, it means that Dino considers everything a simple “object”. You may have noticed that you don’t declare a type when you set a Dino variable or define a function. This differs from the statically-typed nature of the host framework.

In Host Framework
public int add(int a, int b) {
return a + b;
}

var value = add(3, 4); // ok
var sv = add('one', 'two'); // error, will not compile
In Dino Script
def add(a, b){
return a + b;
}

var value = add(3, 4); // ok
var sv = add('one', 'two'); // also ok, returns 'onetwo'

Notice that in the host language, the add method declares a return type (int), and each parameter declares a parameter type (both int in this case). This means that when we attempt to call the add method with string values, the host language compiler will complain.

In Dino, by contrast, we omit any return type information, and parameters are simply identifiers like a and b. This allows calling the add function in Dino with whatever arguments we like – the expression evaluator will just try to add them together, no matter what the “type” of the arguments may be.

This all sounds peachy – we don’t need to bother with type information. And usually, that turns out to be correct. There are, however, some edge cases that cause problems when you pass a Dino function into a native function as a callback.

What is a Delegate?

This section will get a bit dense with terminology and programming concepts. If you don’t care about the underlying reason and just want to know how to make it work, feel free to skip to the next section.

In the native framework, a delegate is a piece of code that defines the signature of a function, but does not provide implementation details. Here is the full definition of a delegate:

public delegate TResult Func<in T1, in T2, out TResult>(T1 arg1, T2 arg2);

Let’s break that down. TResult is the type that will be returned by a method that matches the signature of this delegate. T1 is the type of the first argument, T2 is the type of the second argument. Here is a method that happens to match the signature of that delegate – hey, it looks familiar!

// we have a return type (TResult, int)
// we have a param type (T1, int)
// we have another param type (T2, int)
public int add(int a, int b)
{
return a + b;
}

Because this method (with its implementation details) matches the signature of our delegate, it can be supplied as a “replacement” (thus the name “delegate”) wherever another function wants a callback of that delegate type.

// add any two things together, and let the delegated function do the actual work
public TResult addAnything(Func<T1, T2, TResult> adder, T1 arg1,l T2 arg2)
{
// call the delegate that was passed in
return adder(arg1, arg2);
}

So, What's the Problem?

We'll be expanding the documentation in this section soon. Please contact us if you have questions.

What's the Workaround?

We'll be expanding the documentation in this section soon. Please contact us if you have questions.

How did we do?

Sandbox In-Depth

Style Guidelines

Contact