Modules

Read time: 43 minutes (10775 words)

See also

Text, Chapter 3

You should have a fair idea about the chunks of data we can manage in our programs from your last lecture, and readings. It is time to discuss how we organize our code a bit.

Most programs are not just one huge block of code that is processed from top to bottom. They are actually constructed using building blocks we can design. These blocks are like the major components of a car: the engine, the body, the drive train. These major components are bolted together to make up a car. However, each of these major components are actually made up of smaller components which were combined to built the major assembly.

That is how humans break a complicated thing down into more manageable chunks. We call the process of breaking things down “decomposition”, and the chunks we create are called “modules”

Believe it or not, you already understand the concept of a “module”. I assume you own (or at least have used) a calculator. If that calculator had a button labeled “SQRT” what do you think it did?

Well, DUH! It calculates the square root of some number you enter into the calculator before pressing that button!

True! But what actually happens inside the calculator when you press that button?

Boxes of Code

The answer is fairly simple. A bunch of instructions are activated and the number you entered is processed by those instructions in an attempt to find the square root of that number. we call the number that will be processed the “parameter”. The exact same bunch of instructions are fired off if you enter a different number, then press the button again. Parameters allow us to reuse a block of code to solve a different problem as needed.

In essence, we have taken a set of instructions, placed them in a box, and slapped a name on that box: “SQRT” in this case.

We can activate that box whenever we like, and provide it with a new “parameter” to work on each time.

This is a critically important concept. We can reuse the code in the box, without needing to copy it into our program each time we need to figure out the square root of something!

Formally, we call this box a “module”, although other terms are common used as well:

  • subprogram (a smaller program)

  • subroutine

  • function (from your math days)

  • procedure

They all mean the same thing.

Modules have four basic parts:

All modules have four basic parts:

  • name: which helps users determining what the module does

  • parameters: one or more pieces of data needed by the module to do the work

  • return value: most modules (but not all) will “return” a value to you when they are done.

  • The actual code we place in the box.

Modules are our most fundamental tools to breaking up a big problem into smaller, easier to manage, parts. Done right, we can build the individual modules without worrying about how they will be used. Our job, when building a module, is to make sure the module does exactly what it needs to do! We combine modules to build our big program.

Decomposition

We study real problems looking for ways to break them into smaller parts. This activity is called “Decomposition” and getting good at doing this makes you a very good problem solver.

One obvious way to break up a program is to focus on that “IPO” notion, and build a set of three modules:

  • input: reads all the data needed by the program

  • process: does the actual calculations

  • output: displays the final results

Of course, exactly how the data gets into one module, and passes between modules is not clear at this point. In fact, this is actually not a very good way to break up a many real programs at all. Many common programs will not work well if we try to set them up this way!

Let’s see an example problem were this will not work.

Sample Problem

Read a set of numbers from the user, and calculate the average value of those numbers processed.

For now, just think about doing this using a calculator.

  1. First, we need to clear the calculator. That sets the number in the

    display to zero.

  2. Next, we press the “+” button to add the entered number into the display

  3. Next, we enter a number into the calculator.

  4. Press the “=” key to see the result of adding this new number.

  5. Repeat steps 2 through 4 until all numbers have been entered

  6. Press the “/” key (divide)

  7. Enter the number of numbers you entered (you kept track or that, right?)

8 Press the “=” key to see your final result.

Note

This worked on my Mac, using the calculator program. Try this yourself using a calculator you own, or one on your computer.

I think you can see that we are entering data, processing it, and even displaying it in one big loop. It would be hard to break this up into a set of three IPO modules.

Identifying the parts of a problem that could be carved off into a module takes practice. It helps if you spot something you might need to do a number of times, but modules can only be activated once is needed.

The ideal module is actually a self-contained smaller problem, with its own sets of input, processing, and output parts. Such a smaller problem can be handed to another programmer to solve, leaving others to focus on the bigger problem. The challenge is to make sure we can bolt all the parts together to build our real (big) program that solves our original problem!

Trolls in a box

I used to teach programming to game developers, who always thought in terms of their games. So, I came up with this view of a module:

Pretend you have a really cool module but it is locked up in a box. The box has slots on top, and another slot on the side. You have a bunch of cards on top of the box. On the box is painted a name, something like sqrt.

Inside this box is a “troll”. You know about trolls, right? They are evil dudes we do not want to mess with, so we keep them locked up in our box. We really do not want to open up the box to see what is inside!

Note

Although this seems silly, it is a good analogy! Users of a module have no business worrying about what is inside them. Their job is to use the module properly, not worry about the magic going on inside!

Setting up your parameters

You can pick up a card from the top of the box and write down some value you want to process. We will call this card a “parameter”. You might need more than one parameter to fully provide all the data needed by the troll. Slide each card into the slot on top of the box.

Now for the fun part

Kick the box to wake up the troll.

(sound of furious activity followed by a new card sliding out of the box through the slot on the side)

The Function return

The answer to your problem is found on that final card. This final card is the module’s “return value”.

Not all modules return a value through that side slot. In some cases the furious activity you hear is doing something, but exactly what needs to be determined by looking around. Perhaps the module turned on a light somewhere, or activated a motor, or cleared your screen. You did not exactly get a value on a card, but you got some “side effect” you were after instead. That is fine! Modules can do such things if needed.

Other modules may need nothing in the way of a parameters to do their work. Say we have a module that asks the user for a number to process. We activate the module, handing it nothing. It displays a prompt on the screen, then reads the keys the user typed to get the number. Finally, it hands us the result out the side slot!

What happened inside the box?

When the troll woke up, he picked up the card. In invisible ink that the troll can read was the word “number” followed by the value the fool who kicked the box wrote on the card. The troll has a sheet with instructions on how to take that “number” thing and punch keys on the calculator to figure out something. The troll writes that final something down on a new card and sticks it out the slot in the side of the box. He can then go back to sleep. At least until another fool kicks the box again.

Now, this sounds handy. If we have a bunch of trained trolls, each capable of doing a different task, we can use then to solve complicated problems. Shoot, we might have a super-troll with its own staff of sub-trolls that the super-troll could use to solve really hard problems. Sounds kind of useful.

We will use simple functions when we start using modules. For now, you get the idea (I hope!)

Creating Modules

As we mentioned earlier, modules almost look like complete programs, only on a smaller scale. We can think about them as “IPO” objects:

They have their own “input” in the form of those “parameters” (also called “arguments” in the text).

They have their own “output” in the form of a return value. Not all modules return anything. Some of them just do work. We are happy with the result, even if no “troll” hands us a card!

Modules certainly do processing. That is the code inside the box.

They can also set up private data containers to help them do this work.

Program Data

In a previous lecture, we looked at the idea of setting up containers to hold data, and giving those containers names. We called such containers variables, and we build a bunch of them to hold our data. There are actually two kinds of variables we can set up in our programs:

Global Variables

If we want containers that can be used anywhere in a program, we create them in such a way that they are visible to the entire program. We call these variables “global variables”. These containers are available (visible) to the entire program.

Local Variables

In performing the task inside a module, we can set up private data containers to be used only by that module. We call these data items “local variables”. No code outside of the module can access these containers. They are protected by the box surrounding the module! This is great, because the module is totally self contained. You can pick up a good module from one program, and plant it into a completely different program that needs the same kind of help. This is reusable code”, and it is the ideal kind of component to build.

Programmers build up entire libraries of such modules, and use them in many programs. For example, the “math library” has a ton of useful modules, including our friend, the “square root” module. We also have modules to do trigonometry. Logarithms, and a bunch of things your math teacher wished you remembered! When you need them, they are available in that library,you do not need to write the code to figure all that out yourself!

Using Variables Properly

We use these different kinds of variables to control who can see a variable. If all variables were “global”, it would be possible for some part of your program to accidentally modify a variable when it is not supposed to do that. Later, the code that needs that variable might think is has a proper value, but it actually does not. Your program may go “boom” as a result, and you have to figure out why!

This is where you discover “debugging” the process of figuring out why your program does not work right!

Be Thinking About Modules

As you work through the problems int his class, look for places where there might be a chunk of the problem can be carved off to make a module. It does take practice, but you will end up creating a set of common modules, and you will start to see places where those modules might help in other problems.