This is another relaxing chapter, with two fun rules that let you reuse the same function name: default parameters and overloading.
They can make it look like the same function takes all sorts of different inputs, so you can use these tricks to write an A so that A(3);, A("goat"); and A(3,6); are all legal.
But they’re just shortcuts and tricks. They don’t change the way functions really work.
A default parameter is a shortcut that lets the computer auto-fill parameters in some function calls. Here’s an example of my old setPos function using them. The only new thing (which I haven’t explained yet) are the extra two =’s in the heading:
The first thing to know is if we call it the normal way, like setPos(5,2); it
runs the normal way. Those two =’s will do nothing, like they weren’t even
there.
The new rule is that if the function has an equals-something after a parameter, we can leave it out of the function call. The computer will fill in that value. setPos(4); matches 4 to x and fills in 0 for y. It’s a shortcut for setPos(4, 0);.
setPos(); fills in 0 for x and 0 for y. It’s a shortcut for setPos(0, 0);
The other important thing to understand is that it makes no difference in how the
function works. setPos(3); and setPos(3, 0); are 100% the same thing to the
computer. Both ways, y is 0 and the computer doesn’t care how it got that
way.
Here’s another silly example with strings, showing how some parameters can have defaults, while others don’t:
This says if you leave out the last input, place, it fills it in with "park". If you leave out the last two inputs, it also fills in animal with "dog". But you have to always give one input, name, since it has no default. An example of every way to call it:
There are two ways we usually use them. One is to add a very, very optional extra input. For example:
In our minds, this is a 2-input function. x and y are all we change most of the
time. But in the oddball case when we need to, we can throw in a value for z, like
setPos(-7,4,1).
The other way to see it is as a shortcut for a common value. Suppose my cube
game often has y near the top, at y=4. We might write void setPos(float x,
float y=4). In our minds, this is still a 2-input function, but sometimes
we’ll write setPos(-7); as a shortcut for “the usual height”. Even if we
never do that, we still have a nice built-in reminder that the normal y is
4.
Built-in functions use lots of default parameters. The Unity spin command has a default 4th input which no one ever uses:
The fourth input has a default parameter, which means we can ignore it.
Rotate(0,90,0) is legal. This is a case where it’s telling us that if we know
about rotation spaces, we can pick one. Otherwise the one it gives us is just
fine.
But the fourth input is fun to look at. It’s an enumerated type. We can
look it up. It’s enum Space {Self, World};. In the 4th input, Space
relativeTo=Space.Self, the type is Space, which is really an int that can be
0 or 1. 0 stands for Self and 1 stands for World. Altogether it means we
normally rotate in Self space, but can optionally use World space. For example
Rotate(0,90,0,Space.World).
If you try this, the real command has the word transform in front:
transform.Rotate(0,90,0);.
As usual, inputs are matched left to right exactly in order – it won’t skip any to try to make things work. Suppose we have this:
You don’t have to give this any inputs, but if you do, the first one has to be a
string, for w. A(3); tries to put 3 into w and can’t. It gives you the odd error No
overload for method ‘A’ takes ‘1’ arguments
Because of the left-to-right, no-skipping rule, default parameters have to start from the right. This next function is illegal. It tells you Optional parameter cannot precede required parameters:
The problem is that you have to give it y, since it has no default, which means you also have to give it w. There’s no way to make it ever fill in cow automatically.
You’re allowed to reuse a function name if the parameters are different. This is called
overloading. That’s the entire rule. The rest of this is just examples and how we
usually use that trick.
A different number of inputs lets you reuse the name. For example, we can make a 2 and a 3 input max:
They’re still two completely different functions. But if we type max(
the pop-up shows us both, making it look like there are two versions of
max.
Different types also let us overload a name. For example we can write another version of max with 2 inputs, but both are int’s:
This lets us write int n=max(5, 2); without a cannot-convert error. It runs the
int version. But it’s still nothing special – we have three completely different
functions which happen to share a name.
Here’s a silly overloading example that shows the rules:
In Unity our old Random.Range is overloaded. An int version gives whole numbers, like rolling a die:
The same as before, these are 2 completely different functions. It just feels like 2
versions of Random.Range. They could have named the second one RangeInt, but
most people think it’s nicer to type Random.Range( and look through the
options.
The full rules for overloading are complicated. For example Random.Range(2, 5.0f); has one int and one float. It runs the float version since it’s closer. And if you write float f=Random.Range(1,4); it runs the int version. There are more rules than that, but if you need them it probably means you’ve gone a little too nuts on overloading.
Overloading and default parameters are often combined to make it look like we have one very flexible function. When you type a function name and see the little “1 out of 4” indicator, you can arrow down to see the overloads or versions with and without default parameters.
Here’s an example of where it feels like we have 4 options for setColor, but it’s actually 3 different functions, one of them using a default parm:
The pop-up for setCol will show us these:
Before we had overloading, we gave functions slightly different names like max2f,
max3f for 2 and 3 float max functions, and max2i for the int version. That was
fine. You can still do that. But today almost every computer language has
overloading.
Using overloads has zero effect on the final program, since the compiler takes care of them. It checks the inputs and figures out which one to use, baking that into the compiled code. In fact, it secretly gives them all different names.