Understanding Functions – Return Values

There is a very short list of programming structures you have to learn to be reasonably comfortable in most modern object-oriented languages. Functions are one of them.

In Understanding Functions, we learned that Functions are a way to bundle code statements together into a tight little unit that we can invoke (or “call”) any time we like, and as often as we like. There are two very important features to learn about Functions: Arguments and Return Values. We’ll figure out Return Values in this article.

One Fanta, Please

Vending Machine

We talked about how Functions that accept arguments require exact change. If a Function asks for a String, you have to pass (“pay”) it a String. If it wants an int, you must pass it an int. If it wants two Arrays, a String, and four ints, you have to pass it those seven datatypes in that exact order. If you pass the right datatypes in the wrong order, if you pass the wrong datatypes altogether, or if you pass the wrong number of arguments, you’ll throw a (possibly cryptic) error.

So let’s imagine that Functions are kinda like vending machines. They require exact change, even specifying the types of coins you need to pay (ie five nickels, NOT one quarter). But what do we get for all our trouble? A kick in the pants and we’re sent on our way, that’s what. Wouldn’t it be great if Functions could actually give back to society, instead of being a drain on our charitable resources?

Thanks to return values, they can. A return value is the can of Coke that the Function vending machine spits out when we plug in our coins.

Just as we type (specify a datatype for) our variables, we can also type our Functions. When we do that, we’re saying “this is the type of thing the Function is going to return (give back/pay out/cough up). Here’s how we write a Function that returns a String:

function giveMeGoodNewsOnly() : String
{
    return "good news";
}

There are a few moving parts involved here. Let’s take it step by step.

The type of the return value goes at the end of the Function declaration. We split it out using a colon (two dots), just like when we type a variable. Here’s a punctuation refresher:

Punctuation refresher

And here’s a representation of the Function using colour blocks, because colours are pretty:

Return Values

By adding that datatype to the end of our Function declaration, we’re making a promise: the Function will return (pay out/cough up) something that has that datatype. To live up to that promise, we use the return keyword. Return is the command that pays/spits out/coughs up a value. In the code example above, the giveMeGoodNewsOnly Function is typed String, which means it must return a String. In the statement block (between the curly braces), we use the return keyword to return a String. And all was right with the world.

Where Does the Return Type Go?

So, fine – we return something from our Function. But what happens to that value? Remember when our Pac Man-like code interpreter chewed through the Function call, and packed his suitcase with the arguments?

Call a Function

The code interpreter recognizes this as a Function call …

Bring the Arguments

… and takes the arguments with him in his suitcase.

When the code interpreter finds the function, he unpacks the arguments into the parameters.

Unpack the arguments

At this point, the code interpreter has an empty suitcase. When he reaches a return statement, he packs the value into his suitcase.

Pack the return value

Get packing, Pac Man.

As we saw earlier, the code interpreter returns to the next line after the original function call. But this time, he’s got a suitcase packed with a return value:

[swf]http://www.untoldentertainment.com/blog/img/2010_12_02/returnValueFlow.swf, 600, 500[/swf]

(this is an interactive demonstration! Keep clicking the “Next” button to follow the code interpreter through the example)

Unpacking the Return Value

When the code interpreter arrives from his journey with the return value in tow, we need to somehow capture that return value. Otherwise, the interpreter just throws it away and it disappears into the either.

Here’s a simple example to demonstrate that concept:

6+5;

You know and i know that 6+5 is 11. Your computer knows that too. When you type that into a line of code, the computer adds 6 and 5. And then …? Nothing. We haven’t told the computer to do anything with that result, so it’s a wasted piece of code.

Here are a couple of ways we can make use of the 11 result. We can store the result in a variable (bucket), or we can trace the result to the output/console window:

var result : int = 6+5; // Store the value 11 in a variable called "result"
trace(6+5); // Print 11 to the output window

Note: Unity javascript users should use print or Debug.Log instead of trace to print to the Console window.

It’s the same issue with Functions and their return values. If we call the sayHello Function and it returns a value, the value is going to disappear unless we capture it somehow. Just like the 6+5 example, let’s store the return value in a variable, or print it to the output window:

var greeting : String = sayHello("Jennifer"); // Store the return value "Hello, Jennifer" in a variable called greeting
trace(sayHello("Matthias")); // Print Hello, Matthias to the output window

The code interpreter needs some place to unpack his bags. These are just two ways to capture the return value – there are many, many more. For example, you can add the result to an Array using the Push method (see Understanding Arrays for more info).

You Get a-NOTHING!!!

What do we do about a Function that doesn’t return any value at all? Can we just leave that little section at the end of the declaration blank? Well, you can, but it all depends on how picky your compiler is. You can set the Flash compiler to Strict mode … certain other compilers are strict by default. This means that every variable must be typed (given a datatype), and every Function must also be typed.

The keyword for “no type” is void. If your Function doesn’t return a value, type it as void:

function thisReturnsNothing() : void
{
}

Return Stops the Show

The only really important thing to know about the return keyword is that when the code interpreter chews its way down to that line, it’s like hitting the EJECT button. The interpreter gets booted out of your Function, regardless of whatever statements you may have written beneath it:

function sayHello(playerName : String) : String
{
    return "Hello, " + playerName;
    // This line doesn't get executed.
    // Neither does this one.
    // Nor this one.
    // In fact, anything you write after a return statement gets skipped.
}

Breaking Stuff

As with arguments, there are some great ways to break a Function with return values. In brief, here’s how to do it:

  1. Return a value even though your Function is typed void (or it’s untyped).
  2. Type your Function to return a value, and don’t return a value.
  3. Return a datatype that’s different than the return type declaration.
  4. Write some branching logic so that it’s possible your Function may not return a value.

Let’s look at each of these, and the error statements that pop up when we make each mistake.

1. Return a Value When You Shouldn’t

Here’s an example of a Function that is typed void, but it returns an int:

function whoops():void
{
    return 57;
}

When you do this, here’s the error that the Flash compiler throws:

Scene 1, Layer ‘Layer 1’, Frame 1, Line 3 1051: Return value must be undefined.

That’s a pretty clear error message. Thank you, eggheads.

Here’s the error message you get when you use Unity javascript:

Assets/NewBehaviourScript.js(3,12): BCE0022: Cannot convert ‘int’ to ‘void’.

Again, with a tiny bit of detective work, this error is not too tricky to sort out. The compiler thinks you’re trying to make it force a value of type int to be a value of type void (which is what you’re returning), but this is impossible, even for computers.

2. Promise a Return Value, and then Cop Out

If we type a Function with anything other than void, we’re pledging to return a value. If we don’t return a value of that type, the compiler shows up on our doorstep in the middle of the night with mascara streaking her cheeks, demanding to know why you never do the things you say you’re going to do.

Psycho Girlfriend

You said we would have BABIES! And ints!!!

Here’s an example of a promise a programmer didn’t follow up on with a return statement:

function makeBabiesWithTanya() : int
{
    var numberOfBabiesWeCanHave : int = 17;
    // Honest.
}

So because the return statement is missing, this Function doesn’t actually give Tanya any babies. And that’s when she notices something is up:

Scene 1, Layer ‘Layer 1’, Frame 1, Line 5 1170: Function does not return a value.

This is one of the clearest error messages you’ll ever receive when using Actionscript 3. Let’s see how it looks in Unity javascript:

(no error)

Unity is clearly a lot more easy-going about this type of thing. Remember that when you’re thinking of which one you should invite on a road trip to Vegas.

3. Return the Wrong Datatype

If the Function is typed int, we gotta return an int. If it’s typed Array, we gotta return an array. Here’s an obvious boob:

function iAmConfused() : int
{
    return "nyearrrghhh";
}

This Function is typed int, but we’re returning a String. Here’s the Flash error:

Scene 1, Layer ‘Layer 1’, Frame 1, Line 3 1067: Implicit coercion of a value of type String to an unrelated type int.

Nice and clear. And in Unity javascript:

Assets/NewBehaviourScript.js(3,12): BCE0022: Cannot convert ‘String’ to ‘int’.

These are both very similar, and they do a pretty good job at getting the point across.

4. Faulty Logic

The Labyrinth

If you write a Function that should return a value, and you load it up with branching conditional logic, the compiler will actually step through that logic to make sure a value gets returned. Here’s an example of a logic structure that may never return the value promised by the Function:

function badLogic(playerName : String) : String
{
     if(playerName == "Pete")
     {
          return "Hi, Pete!";
     } else if(playerName == "Carl") {
          return "Hi, Carl!";
     }
}

So if the playerName is Pete, we return “Hi, Pete”, and if the playerName is Carl, we return “Hi, Carl”. But what if the playerName is Suzie, Jasmine, Turk, Paolo or Ferdinand? In that case, neither of the statements will get executed, and so it’s possible that the Function will not return a value.

Here’s what the Actionscript 3 compiler has to say about that:

Scene 1, Layer ‘Layer 1’, Frame 1, Line 9 1170: Function does not return a value.

Clear as crystal! And now, Unity javascript:

(no error)

Hmm. Now we’re up against a situation where permissive coding isn’t always a good thing. As a very new programmer, you might think “the fewer errors, the better”. But if you’re expecting that Function to return a value, and it somehow doesn’t, wouldn’t it be more helpful to see an error telling you what went wrong?

Answer: yes. Yes it would.

Your Triumphant Return

Those are the essentials of writing Functions that return values. Together with Understanding Functions and Understanding Functions – Arguments, you should have a complete picture of what Functions are and what they can do. But this is the HOW, not then WHEN of it. These articles just discuss the building blocks of Object-Oriented Programming. Assembly instructions, and even freestyle building – are entirely different matters altogether.

For more Flash AS3 Tutorials and a pile of other useful stuff, check out our Flash and Actionscript 911 feature.

Leave a Reply

Your email address will not be published. Required fields are marked *