Advertisement:

Skystone Software

http://www.SkystoneSoftware.com

.NET Programming

Subroutine and Function Basics for Beginners
Published: 3/18/2006

Beginner programmers sometimes have some trouble understanding the need for and inner workings of subroutines and functions. This, I think, is one of those learning blocks that really raises you a step up once you've mastered it, but can be frustrating to get past for people learning to program with no programming background. I learned how to program Basic on an Apple II+ back when I was 8 years old (thanks Dad!), before there were subroutines and functions. All we had was Goto, GoSub, and Return, and we LIKED it. I think that learning how to program with those limitations helped me intuitively understand subroutines and functions when I first was exposed to Visual Basic, because they simply made sense to me - it was something that made the language better than plain old Basic. Too many times, entry-level programming courses will teach the "how" without bothering with the "why". This makes it hard for someone learning how to program with zero prior experience to understand the need for routines and functions intuitively. This primer is for those people.

Let's start simple. Envision, if you will, a form (Form1) that has 4 textboxes (txtInput1, txtInput2, txtInput3, txtInput4) and two buttons (Button1, Button2) on it. Your goal is to set the text of all of the TextBoxes to read "Hello!" when the form loads, "Hello World!" when the first button is pressed, and back to "Hello!" when the second button is pressed. Here's how you might do this in the code on your form:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.txtInput1.Text = "Hello"
        Me.txtInput2.Text = "Hello"
        Me.txtInput3.Text = "Hello"
        Me.txtInput4.Text = "Hello"
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.txtInput1.Text = "Hello World!"
        Me.txtInput2.Text = "Hello World!"
        Me.txtInput3.Text = "Hello World!"
        Me.txtInput4.Text = "Hello World!"
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Me.txtInput1.Text = "Hello"
        Me.txtInput2.Text = "Hello"
        Me.txtInput3.Text = "Hello"
        Me.txtInput4.Text = "Hello"
    End Sub

Inside the Form Load event we are setting the initial values for each TextBox directly and inside the corresponding click events for the buttons we are setting the text values directly.

This will work fine, but you might have already noticed that we have the same code in two different places:

        Me.txtInput1.Text = "Hello"
        Me.txtInput2.Text = "Hello"
        Me.txtInput3.Text = "Hello"
        Me.txtInput4.Text = "Hello"

This code is duplicated in both in the Form Load event handler and the Click event handler for the second button. If only there was a way to avoid typing this code twice!

Introducing the subroutine. A subroutine (Sub) is a wrapper around a set of code, and its purpose is to create a "pocket" of code than can be called from anywhere in your application at any time any number of times. Here's how we can refactor the above code to be more efficient:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Call SetTextboxText()
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Me.txtInput1.Text = "Hello World!"
        Me.txtInput2.Text = "Hello World!"
        Me.txtInput3.Text = "Hello World!"
        Me.txtInput4.Text = "Hello World!"
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Call SetTextboxText()
    End Sub

    Private Sub SetTextboxText()
        Me.txtInput1.Text = "Hello"
        Me.txtInput2.Text = "Hello"
        Me.txtInput3.Text = "Hello"
        Me.txtInput4.Text = "Hello"
    End Sub

Right, now we've consolidated our code so that we have no duplicate code! However, because I'm a perfectionist I'm starting to notice that we have some similar code in two different places and am wondering if we can't further consolidate these 8 lines of code:

        Me.txtInput1.Text = "Hello World!"
        Me.txtInput2.Text = "Hello World!"
        Me.txtInput3.Text = "Hello World!"
        Me.txtInput4.Text = "Hello World!"

        Me.txtInput1.Text = "Hello"
        Me.txtInput2.Text = "Hello"
        Me.txtInput3.Text = "Hello"
        Me.txtInput4.Text = "Hello"

The only difference between the two blocks of code are the literal strings (meaning the value entered in between quotes as opposed to stored in a variable) "Hello" and "Hello World!". If only there was some way to call our SetTextboxText routine at different times and have it assign different text to the textboxes each time depending on the context of the subroutine call...

Enter subroutine parameters! If we change the definition of our subroutine to accept a parameter, we can use that parameter to give different context to our subroutine depending on how it is called. Here's the new definition of our subroutine:

    Private Sub SetTextboxText(ByVal TextValue As String)
        Me.txtInput1.Text = TextValue
        Me.txtInput2.Text = TextValue
        Me.txtInput3.Text = TextValue
        Me.txtInput4.Text = TextValue
    End Sub

I've added the parameter TextValue to the definition of the subroutine. Parameters are just variables with a scope extending from the start of the subroutine to the end, and as such they have to be declared as a specific type. This particular parameter is carrying a text value into the subroutine, so I've defined it as a String. This means that we can define the value of TextValue when we call the subroutine "SetTextboxText" by specifying its value when we call it, like this:

Call SetTextboxText("Hello World!")

...so our new form code becomes:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Call SetTextboxText("Hello")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Call SetTextboxText("Hello World!")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Call SetTextboxText("Hello")
    End Sub

    Private Sub SetTextboxText(ByVal TextValue As String)
        Me.txtInput1.Text = TextValue
        Me.txtInput2.Text = TextValue
        Me.txtInput3.Text = TextValue
        Me.txtInput4.Text = TextValue
    End Sub

Now that's efficient code!

Here's where our new design really comes in handy: let's add another TextBox to the form and include it in the mix, setting its text when we set the text of the other TextBoxes. Our new code becomes:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Call SetTextboxText("Hello")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Call SetTextboxText("Hello World!")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Call SetTextboxText("Hello")
    End Sub

    Private Sub SetTextboxText(ByVal TextValue As String)
        Me.txtInput1.Text = TextValue
        Me.txtInput2.Text = TextValue
        Me.txtInput3.Text = TextValue
        Me.txtInput4.Text = TextValue
        Me.txtInput5.Text = TextValue
    End Sub

So instead of adding 3 new lines of code (like we would have had to with our original design), we simply add one line!

Now, what if we wanted to display a MessageBox to the user when they clicked either of the buttons telling them how many TextBox controls were updated as a result of the button click? We could do this:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Call SetTextboxText("Hello")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Call SetTextboxText("Hello World!")
        MessageBox.Show(Me, "5 TextBoxes were updated!")           
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Call SetTextboxText("Hello")
        MessageBox.Show(Me, "5 TextBoxes were updated!")
    End Sub

    Private Sub SetTextboxText(ByVal TextValue As String)
        Me.txtInput1.Text = TextValue
        Me.txtInput2.Text = TextValue
        Me.txtInput3.Text = TextValue
        Me.txtInput4.Text = TextValue
        Me.txtInput5.Text = TextValue
    End Sub

... but that's not really good design, is it? Now if we add (or remove) TextBoxes to the form like we just did, we have to add one line of code in the SetTextboxText routine and modify each of the Messagebox.Show lines in our button clicks to remain accurate. If only there was a way for our SetTextboxText subroutine to tell us how many TextBoxes it updated...

Introducing the Function! Functions are exactly like subroutines with one notable difference: they return a value to the calling code. Here's an example of a function that simply returns a string value:

    Private Function GetStringValue() As String    
        Return "Hello World!"
    End Function

When you call a function you don't use the "Call" keyword. Instead, you assign the return value of the function to a variable. This function returns a String, so we would declare a String variable to hold the result:

    Dim sValue As String
    sValue = GetStringValue()
    MessageBox.Show(Me, sValue)

    Private Function GetStringValue() As String    
        Return "Hello World!"
    End Function

If you run this code you will end up with a MessageBox that displays the text "Hello World!".

Now let's apply this concept to our original code. We will modify our SetTextboxText to become a function that returns an Integer that will represent the number of Textboxes that were updated as a result of the function call (how do we know that's what the return value means? It's not entirely clear from the name of the function, so we would have to have some good documentation of our code to know that's what the result of the function meant). We will then assign this value to an Integer variable, and display it in our MessageBox in the button click events. Here's our code:

    Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Call SetTextboxText("Hello")
    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Dim iItemsUpdated As Integer
        iItemsUpdated = SetTextboxText("Hello World!")
        MessageBox.Show(Me, iItemsUpdated.ToString() & " TextBoxes were updated!")
    End Sub

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
        Dim iItemsUpdated As Integer
        iItemsUpdated = SetTextboxText("Hello")
        MessageBox.Show(Me, iItemsUpdated.ToString() & " TextBoxes were updated!")
    End Sub

    Private Function SetTextboxText(ByVal TextValue As String) As Integer
        Me.txtInput1.Text = TextValue
        Me.txtInput2.Text = TextValue
        Me.txtInput3.Text = TextValue
        Me.txtInput4.Text = TextValue
        Me.txtInput5.Text = TextValue
        Return 5
    End Function

Notice that in the Form Load event handler, we are still using Call when we call the function. That's OK, because we are ignoring the return code in that event. Notice also that even though our function definition contains a parameter of type String, it returns a value of type Integer.

This primer was meant as in introduction to the world of non-linear programming, in which code can be encapsulated for reuse and efficientcy. Subroutines are just pockets of code that can be executed, adjusting their behavior based on different parameters passed into them, and functions are simply subroutines that return a value to the calling code.



Written by Scott Waletzko for Skystone Software.
Copyright 2005-2007 by Echosoft Design Studios, LLC, All Rights Reserved.