Can someone distill into proper English what a delegate is?

I have a function:

public long GiveMeTwoTimesTwo()
{
    return 2 * 2;
}

This function sucks. What if I want 3 * 3?

public long GiveMeThreeTimesThree()
{
    return 3 * 3;
}

Too much typing. I’m lazy!

public long SquareOf(int n)
{
    return n * n;
}

My SquareOf function doesn’t care what n is. It will operate properly for any n passed in. It doesn’t know exactly what number n is, but it does know that n is an integer. You can’t pass "Haha not an integer" into SquareOf.

Here’s another function:

public void DoSomethingRad()
{
    int x = 4;
    long y = SquareOf(x);
    Console.WriteLine(y);
}

Contrary to its name, DoSomethingRad doesn’t actually do anything rad. However, it does write the SquareOf(4) which is 16. Can we change it to be less boring?

public void DoSomethingRad(int numberToSquare)
{
    long y = SquareOf(numberToSquare);
    Console.WriteLine(y);
}

DoSomethingRad is clearly still pretty fail. But at least now we can pass in a number to square, so it won’t write 16 every time. (It’ll write 1, or 4, or 9, or 16, or… zzzz still kinda boring).

It’d be nice if there was a way to change what happens to the number passed in. Maybe we don’t want to square it; maybe we want to cube it, or subtract it from 69 (number chosen at random from my head).

On further inspection, it seems as though the only part of SquareOf that DoSomethingRad cares about is that we can give it an integer (numberToSquare) and that it gives us a long (because we put its return value in y and y is a long).

public long CubeOf(int n)
{
    return n * n * n;
}

public void DoSomethingLeet(int numberToSquare)
{
    long y = CubeOf(numberToSquare);
    Console.WriteLine(y);
}

See how similar DoSomethingLeet is to DoSomethingRad? If only there was a way to pass in behavior (DoX()) instead of just data (int n)…

So now if we want to write a square of a number, we can DoSomethingRad and if we want to write the cube of a number, we can DoSomethingLeet. So if we want to write the number subtracted from 69, do we have to make another method, DoSomethingCool? No, because that takes too damn much typing (and more importantly, it hinders our ability to alter interesting behavior by changing only one aspect of our program).

So we arrive at:

public long Radlicious(int doSomethingToMe, Func<int, long> doSomething)
{
    long y = doSomething(doSomethingToMe);
    Console.WriteLine(y);
}

We can call this method by writing this:

Radlicious(77, SquareOf);

Func<int, long> is a special kind of delegate. It stores behavior that accepts integers and spits out longs. We’re not sure what the method it points to is going to do with any given integer we pass; all we know is that, whatever happens, we are going to get a long back.

We don’t have to give any parameters to SquareOf because Func<int, long> describes behavior, not data. Calling Radlicious(77, SquareOf) just gives Radlicious the general behavior of SquareOf (“I take a number and return its square”), not what SquareOf will do to any specific integer.

Now if you have understood what I am saying, then you have already one-upped me, for I myself don’t really get this stuff.

* END ANSWER, BEGIN WANDERING IDIOCY *

I mean, it seems like ints could be perceived as just really boring behavior:

static int Nine()
{
    return 9;
}

That said, the line between what is data and behavior appears to blur, with what is normally perceived as data is simply boring-ass behavior.

Of course, one could imagine super “interesting” behavior, that takes all sorts of abstract parameters, but requires a ton of information to be able to call it. What if it required us to provide the source code that it would compile and run for us?

Well, then our abstraction seems to have gotten us all the way back to square one. We have behavior so abstract it requires the entire source code of our program to determine what it’s going to do. This is fully indeterminate behavior: the function can do anything, but it has to be provided with everything to determine what it does. On the other hand, fully determinate behavior, such as Nine(), doesn’t need any additional information, but can’t do anything other than return 9.

So what? I don’t know.

Leave a Comment