ASP.NET Basics (part 6): Fully Function-al

Modularize your code in C# by abstracting it into functions.

The Next Big Thing

All the code you've seen over the past few weeks has been what might be called linear - written such that it is executed sequentially, one line after another. Sure, I've added a few "if" and "for" loops for variety, and even thrown in a "switch" here and there to break up the monotony - but by and large, the code in previous sections has been written to resemble a straight line.

Well, it's time to add a few swoops and swirls to the way you code, just to make sure you don't get bored (this also comes in handy if you need to confuse your boss). Enter this week's tutorial, which attempts to address the problem by teaching you all you need to know about a programming construct called a "function".

Ask a geek to define the term "function", and he'll probably tell you that a function is "a block of statements that can be grouped together as a named entity." Since this is a tutorial on ASP.NET, not the language Geek, I'll simplify that definition a little: a function is simply a set of program statements which perform a specific task, and which can be "called", or executed, from anywhere in your program.

Every programming language comes with its own built-in functions and typically also allows developers to define their own functions. For example, if I had a series of numbers, and I wanted to reduce each of them by 20%, I could pull out my calculator and do it manually....or I could write a simple C# function called cheatTheTaxman() and have it do the heavy lifting for me.

There are two important reasons why functions are a Good Thing. First, a user-defined function allows you to separate your code into easily identifiable subsections, thereby making it easier to understand and debug. And second, a function makes your program modular, allowing you to write a piece of code once and then re-use it multiple times within the same program.

The Right Spirit

Let's take a simple example, which demonstrates how to define a function and call it from different places within a C# script:

<script language="c#" runat="server">

// define a function
void guaranteedPickMeUp()
{
    Response.Write("Long Island Iced Tea");
}

void Page_Load()
{

    // the first question...
    Response.Write("What's the only thing that cheers me up when I'm down?<br>");

    // call the function
    guaranteedPickMeUp();

    // ... followed by another
    Response.Write("<br>What contains a virtual menagerie of spirits, guaranteed to leave your head banging in the morning?<br>");

    // call the function
    guaranteedPickMeUp();
}
</script>
<html>
<head><title>A Few Drinks</title></head>
<body>
</body>
</html>

View it in your browser - you should see something like this:

Let's take this line by line. The first thing I've done in my C# script is define a new function with the "function" keyword; this keyword is followed by the name of the function and the data type of the return value of the function. I have used "void" here because our function, in its current state does not return any value (more on this at a later date, though). In the example above, the function has been named "guaranteedPickMeUp".

All the program code attached to that function is then placed within a pair of curly braces - this program code could contain loops, conditional statements, calls to other functions, or calls to other C# functions. Function names are case-sensitive in C#, so be careful when invoking them.

Here's the typical format for a function:

return_data_type function_name ( optional function arguments )
{
    statement 1;
    statement 2;
    statement 3;
    .
    .
    .
    statement n;
}

Turning Up The Heat

By default, when a function is invoked, it always generates a "return value". This return value can either be a special return type called "void", or a value explicitly returned via the "return" statement. I have already demonstrated the use of "void" for my "guaranteedPickMeUp" function, which does not return any value. But how about a function that does return a value?

Here's an example of how a return value works.

<script language="c#" runat="server">

// define a function
double tempConv()
{
        double celsius = 35;
        double fahrenheit;

        fahrenheit = (celsius * 1.8) + 32;

        return fahrenheit;
}

void Page_Load()
{
    string result;

    result = tempConv().ToString();
    output.Text = "35 Celsius is " + result + " Fahrenheit.";

}
</script>
<html>
<head><title>Turning Up The Heat</title></head>
<body>
<asp:label id="output" runat="server" />
</body>
</html>

The output is as follows:

In this case, the value of the last expression evaluated within the function is assigned to the variable "result" when the function is invoked from within the program. Note that the return value must be explicitly specified within the function definition via the "return" statement, and the data type of this return value must be specified in the first line of the function definition, before the name; failure to do either of these will cause the C# compiler to barf all over your screen.

To illustrate this, consider the output if the "return" statement is eliminated from the function definition above.

Sweet Tooth

Of course, it's also possible to specify an explicit return value with the "return" statement, as in the next example

<script language="c#" runat="server">

// define and initialize variable
int time = 9;

// define a function
string whatYouDoing()
{

    // check the condition
    if (time == 9)
    {
        return "On my way to work";

    }
    else if (time == 6)
    {
        return "Done with work, on my way to dinner with friends";
    }
    else
    {
        return "I'm sleeping";
    }
}

void Page_Load()
{
    answer.Text = "Right now? " + whatYouDoing();

}
</script>
<html>
<head><title>Wassup?</title></head>
<body>
Hi, what are you doing right now?<br />
<asp:label id="answer" runat="server" />
</body>
</html>

Notice how the function is able to read the values of variables defined outside the function; this is related to variable scope in C#, and I plan to discuss it in detail a little further down.

Return values need not be numbers or strings alone - a function can just as easily return an array, as demonstrated in the following example:

<script language="c#" runat="server">

// define a function
// to return the dessert
// menu as an array
string [] DessertMenu()
{
    string [] desserts = {"chocolate mousse", "tiramisu", "apple pie", "chocolate chip cookies", "caramel custard", "butter scotch icecream", "blackforest cake"};
    return desserts;
}

void Page_Load()
{
    // get the system time
    DateTime date = System.DateTime.Now;

    // cast the day of the week
    // as an integer
    int day = (int) date.DayOfWeek;

    // define an array to
    // to store our dessert array
    string [] menu;

    // call the function
    menu = DessertMenu();

    // write the day of the week…
    today.Text = date.DayOfWeek.ToString();

    // ... and the dessert for the day
    special.Text = menu[day];

}
</script>
<html>
<head><title>Sweet Tooth</title></head>
<body>
It's <asp:label id="today" runat="server" /> today, and our chef's whipped up some great <asp:label id="special" runat="server" /> for today's special. Would you like some?
</body>
</html>

This is what you should see in the browser.

Passing The Buck

Now, if you've been paying attention, you've seen how functions can help you segregate blocks of code, and use the same piece of code over and over again, thereby eliminating unnecessary duplication. But this is just the tip of the iceberg...

The functions you've seen thus far are largely static, in that the variables they use are already defined. But it's also possible to pass variables to a function from the main program - these variables are called "arguments", and they add a whole new level of power and flexibility to your code.

To illustrate this, let's go back a couple of pages and revisit the tempConv() function.

double tempConv()
{
        double celsius = 35;
        double fahrenheit;

        fahrenheit = (celsius * 1.8) + 32;

        return fahrenheit;
}

As is, this function will always calculate the Fahrenheit equivalent of 35 degrees Celsius, no matter how many times you run it or how many roses you buy it. However, it would be so much more useful if it could be modified to accept any value, and return the Fahrenheit equivalent of that value to the calling program.

This is where arguments come in - they allow you to define placeholders, if you will, for certain variables; these variables are provided at run-time by the main program.

Let's now modify the tempConv() example to accept an argument.

<script language="c#" runat="server">

// define a function
double tempConv(double temperature)
{
        double fahrenheit;

        fahrenheit = (temperature * 1.8) + 32;

        return fahrenheit;
}

void Page_Load()
{
    string result;

    double alpha = 45;

    result = tempConv(alpha).ToString();
    output.Text = alpha.ToString() + " Celsius is " + result + " Fahrenheit.";

}
</script>
<html>
<head><title>Turning Up The Heat</title></head>
<body>
<asp:label id="output" runat="server" />
</body>
</html>

And now, when the tempConv() function is called with an argument, the argument is assigned to the placeholder variable "temperature" within the function, and then acted upon by the code within the function definition.

Note that it's mandatory to specify the data type of the arguments being passed to the function.

It's also possible to pass more than one argument to a function - as the following example demonstrates.

<script language="c#" runat="server">

// define a function
string addIt(string item1, string item2, string item3)
{
    return item1 + item2 + item3;
}

void Page_Load()
{
    output.Text = addIt("hello", "-", "john");

}
</script>
<html>
<head><title></title></head>
<body>
<asp:label id="output" runat="server" />
</body>
</html>

And its output.

Going Nowhere

The order in which arguments are passed to a function is important - the following example assumes that the name is passed as the first argument, and the place as the second.

<script language="c#" runat="server">

// define a function
string User(string name, string place)
{
    return "Hello, " + name + ". How strange that we both live in " + place;

}

void Page_Load()
{
    output.Text = User("Brother Moose", "Erehwon");

}
</script>
<html>
<head><title> </title></head>
<body>
<asp:label id="output" runat="server" />
</body>
</html>

But if you get the order wrong, you may get unexpected results. For example, if you reversed the order in which arguments are passed to the function, as below,

void Page_Load()
{
    output.Text = User("Erewhon", "Brother Moose");

}

this is what you'd see:

All these examples have one thing in common - the list of arguments is fixed. Look what happens if you pass an extra argument to the User() function above,

void Page_Load()
{
    output.Text = User("Harry the Hedgehog", "The Briar Patch", "male");

}

or miss out on a parameter when calling the function.

void Page_Load()
{
    output.Text = User("Harry the Hedgehog");

}
[/code

In both case, the C# compiler will complain with this ugly error:

<img src="image8.gif" />

## First Date

If you've programmed in other languages before, you'll know that generally, a function can return only a single value. However, this does not hold true for functions in C#, which can return more than one value. Take a look:

<script language="c#" runat="server">

// define a function string User(string name, string place, out string comment) { comment = "Care to join me for some coffee tonight?"; return "Hello, " + name + ". How strange that we both live in " + place;

}

void Page_Load() { string propose; output.Text = User("FunkyChameleon", "London", out propose); output.Text = output.Text + "<br>" + propose;

} <html> <head>``<title>The Funky Chameleon <body> `


There are two things to look for here. First, take a look at the updated "User" function.

string User(string name, string place, out string comment) { comment = "Care to join me for some coffee tonight?"; return "Hello, " + name + ". How strange that we both live in " + place;

}


I have added a new parameter named "comment" to the list of function arguments, prefixed with the keyword "out". This little addition instructs the C# compiler to allow the function to assign a value to this "comment" variable, which is then transferred to a variable specified when the function is invoked. This is clearly visible in the lower half of the script.
output.Text = User("FunkyChameleon", "London", out propose);

Here, I have defined a variable named "propose" to pass as a parameter to the updated "User" function. Once the "User" function is invoked, the value assigned to the function variable "comment" is transferred to the "propose" variable once the function has completed executing. Note the use of the "out" keyword in the function invocation as well, to map the function's return argument to the caller's variable.

<img src="../../../data/archives/trog/collateral/00219/image9.gif" />

## Flavour Of The Month

Let's now talk a little bit about the variables used within a function, and their relationship with variables in the outside world. Usually, the variables used within a function are "local" - that is, the values assigned to them, and the changes made to them, are restricted to the function space alone.

For a clearer example of what this means, consider this simple example.

<script language="c#" runat="server">

// define a function void changeFlavour() { string flavour = "tangerine"; Response.Write("(in changeFlavour) Today's flavour is " + flavour + ".<br>"); }

void changeFlavourAgain() { string flavour = "raspberry"; Response.Write("(in changeFlavourAgain) Today's flavour is " + flavour + ".<br>");

}

void Page_Load() {

// invoke changeFlavour function
changeFlavour();

// invoke changeFlavourAgain function
changeFlavourAgain();

// invoke changeFlavour function
changeFlavour();

} <html> <head>``<title>Flavour of the Month <body>


And here's what you'll see:

<img src="../../../data/archives/trog/collateral/00219/image10.gif" />

If you take a closer look at the two functions, you will notice that both of them of define a variable called "flavour". For each invocation of the functions, a new instance of "flavour" is created, independent of any previous or subsequent reference. Such variables are aptly called "local" variables because they only exist within the function in which they are defined, and cannot be accessed outside that function.

When you attempt to access a function variable outside the function, you'll get an error - take a look at the next example and its output (or the lack of it).

<script language="c#" runat="server">

// define a function void changeFlavour() { string flavour = "tangerine"; Response.Write("(in changeFlavour) Today's flavour is " + flavour + ".<br>"); }

void Page_Load() {

changeFlavour();

flavour = "raspberry";

Response.Write("Today's flavour is " + flavour + ".`<br>`");

} <html> <head>``<title>Flavour of the Month <body>


<img src="../../../data/archives/trog/collateral/00219/image11.gif" />

Not a pretty sight. However, this doesn't mean you can't do it - all it means is that you need to declare the variable in the "global" scope.

What is the "global" scope? All variables that are defined outside the functions but within valid ASP.NET <script> tags are defined in the global scope. The following rewrite of the previous example should help to make this clearer:

<script language="c#" runat="server">

// define a global variable string flavour = "tangerine";

// define a function void changeFlavour() { flavour = "chocolate"; Response.Write("No way! I want " + flavour + "."); }

void Page_Load() {

Response.Write("Today's flavour is " + flavour + ".`<br>`");

// try to access the global variable
flavour = "raspberry";
Response.Write("Now its " + flavour + ".`<br>`");

// invoke changeFlavour function
changeFlavour();

} <html> <head>``<title>Flavour of the Month <body>



And now, when you view it,

<img src="../../../data/archives/trog/collateral/00219/image12.gif" />

The crucial thing to note here is where the "flavour" variable has been defined. Since I've defined it outside all the function blocks, it immediately has global scope and can thus be manipulated from inside other functions as well as within the main body of the program...without the doubtful pleasure of a compiler error.

And that just about concludes this article. This time, you've taken a big step towards better software design, by learning how to abstract parts of your C# code into reusable functions. You've learned how to add flexibility to your functions by allowing them to accept different arguments, and how to obtain one (or more) return values from them. Finally, you've learned a little bit about how C# treats variables inside and outside functions.

Readers with a sharp memory will remember that I had introduced a nebulous thing called a "server control", way back in the first part of this series. I had gone on to explain the concept of an ASP.NET "label" control and how it could be used to avoid spaghetti-style code. In the next article, I will go beyond the plain ol' label control and give you a proper introduction to the server controls available for use in your ASP.NET scripts. These include the "textbox" control, the "dropdownlist" control, the "listbox" control, the "radiobutton" control, and many more. So make sure you come back for that one!

Note: Examples are illustrative only, and are not meant for a production
environment. Melonfire provides no warranties or support for the source
code described in this article. YMMV!
This article was first published on 29 Sep 2003.