Advertisement

Wednesday, 22 March 2017

Local variables, parameters and return values in Small Basic

Have you ever written a program with a bug in it? Of course you have!
Here's a technique that might help avoid some of the trickier ones.

Of course, we've all written code with bugs in. Part of the skill of programming is being able to translate the solution to a problem into programming code. Another skill is to find the errors in either the original solution, or the way that you coded it.

The development of programming languages has often been driven by the need to reduce the potential for bugs and speed up development. However, fun though it is, Small Basic lacks some of the fundamental features of modern programming languages.

This is not a criticism, Small Basic was designed to be... well small. And being small it is easy to learn and use to write simple programs. However, as your programs begin to get more complex, you might, unless you are very disciplined, run into problems.

(If you are already familiar with the concepts of local variables, parameters and return values, from another language feel free to skip to the heading 'Local variables in Small Basic')


Local variables

One of the things that it is very easy to do, is to lose track of the variable names that you are using. All variables in SB are what is known as 'global', i.e. they can be seen and changed by any part of the program. This might seem a good idea, but the problem is that, if you inadvertently use the same variable name in a subroutine as you have in the main part of the program, you might accidentally overwrite the value that is being used in the main program resulting potentially very obscure and hard to find errors.

It is for this reason that languages such as C#, Java, and indeed most programming languages, have the concept of 'local' variables. These have a restricted scope - if they are created in a subroutine, then they only exist within that subroutine. As a result a variable called  'x' in a subroutine is a different variable to one with the same name in the main program (or, indeed, in another subroutine). The concept of local variables provides a protection against accidentally writing values to variables whose names clash.

One consequence of this, which is extremely useful in programming teams, is that you can safely incorporate a subroutine written by somebody else into your own program. You don't need to know what variable names it uses, or even how it works, you can treat it as a 'black box' that has a particular function that you want to use.

Parameters and return values

"But", I hear you say, "if local variables are private to their subroutine, how does the subroutine have any effect on the rest of the program?" Good question! There are two answers. The first is that subroutines still have access to the 'global' variables created in the main program. But a second, and safer (for the programmer) answer is the use of parameters and return values.

These are basically a communication system for subroutines. Parameters allow us to pass values into the subroutine and return values are a mechanism for getting a value out again.

We already use parameters in Small Basic when we create a things like graphics or text windows and shapes. The parameters are the values that go in brackets. In other languages, such as C#, subroutines can take parameters, too.

Here's an example of a function (the equivalent of a subroutine) with parameters in C#:

   add(10,20);

   function add(int a, int b){
      int c = a + b;
   }

The first line calls the function 'add' with parameter values 10, 20.

The code for the function specifies the parameters that must be passed and call them 'a' and 'b'. The function then adds 'a' and 'b' together and assigns the result to a local variable 'c'. Now, as I mentioned earlier, local variables only exist within the subroutine where they are created. So, the main part of the program cannot access the value of 'c'.

So how do we get the result back to the main program? With a return value.

   int result = add(10,20);

   function add(int a, int b){
      int c = a + b;
      return c;
   }

This new version of the program introduces a return statement into the function which allows us to use the subroutine call in an assignment statement. Here the result of the addition performed in the function 'add' is put into the variable 'result'.

You will have seen this sort of thing when using the built in functions in Small Basic.

Unfortunately we can't do the same thing with subroutines in SB. But we can mimic it.

Local variables in Small Basic

Now, as I explained above, you can't really use local variables in SB. But you can mimic them. The idea is to ensure that the variables used in a subroutine will only be used by that subroutine and nowhere else in the program.

We can do this by implementing some simple rules:

  1. variables used in a subroutine must have unique names, 
  2. subroutine variables must be recognisable as subroutine variables,
  3. they must not be used anywhere else in the program.

Simple enough. Here's how:

  1. subroutine variable names should be prefixed with the subroutine name,
  2. the name should be prefixed with a special character e.g. '_' (the underscore character),
  3. no variables in the main program may start with that special character.

So, if we have a subroutine called 'add' that adds two numbers together and puts the result in a third variable, we can call the three variables '_add_firstNum', '_add_secondNum', '_add_result'. Ok, it takes a bit more typing but it is simple enough to implement. And you can see that no other subroutine will use variables with the same names because they won't be called 'add' and the variable name will not be used in the main program because we don't allow main program variables to start with an underscore character.

Parameters and returns values in Small Basic.

That's local variables sorted but we still to be able to pass values into a subroutine and then get a value out again. In our 'add' subroutine, we need to pass in 2 values (the ones to be added) and return one (the result).

We do this using a stack. If you are not clear about how a stack works, you can simply imagine a pile of values; if you place a new value on top of the pile, this is called pushing onto the stack, and if you take a value from the top of the pile, this is popping off of the stack. So the last value that is pushed onto the top is the first value that will be popped off.

To pass parameters to a subroutine, we push them onto a stack. The first lines in the subroutine then pop the values off of the stack into local variables. The subroutine then performs whatever functions it neds to, and then the result is pushed onto the stack.

In the main program, immediately after the subroutine call, the result from the subroutine is popped off of the stack.

The following program is deliberately as simple as I could make it and shows the techniques described above. It uses a simple subroutine called 'add' that adds two numbers together and returns the result of that addition.  the comments in the program should make it clear what is going on.

'
' Program to demonstrate how local variables, parameters and return values
' can be mimicked in Small Basic subroutines.
'
' To provide 'local' variables we simply prefix the variable name with the subroutine name
' Since the subroutines need to have a unique names we can ensure that they are not used
' elsewere.
'
' Parameters and return values are implemented using a stack
' Before calling a subroutine the required parameters are pushed onto the stack (in the
' right order!)  and then popped off at the beginning of the subroutine.
' Return values are pushed onto the stack at the end of the subroutine and popped off
' imediately after the subroutine call

'Main program starts here
'===================

' First create a stack name
s = "stack"

'We have a simple subroutine that adds two numbers together and thus takes two
' parameters. We push the values for those parameters onto the stack
Stack.PushValue(s,10)
Stack.PushValue(s,20)

' Now we call the subroutine
Add()

' the subroutine has done its job so we can now pop the result off the stack
' and print it
TextWindow.Write("The result is: ")
TextWindow.WriteLine(Stack.PopValue(s))

'End of main program
'================

' Subroutine Add takes two numeric parameters adds them together
' and returns the result of the addition
Sub Add
  ' pop the parameters of the stack into 'local' variables
  _add_firstNum = Stack.PopValue(s)
  _add_secondNum = Stack.PopValue(s)

  'do the addition
  _add_result = _add_firstNum + _add_secondNum

  ' push the return value onto the stack
  Stack.PushValue(s,_add_result)
EndSub



So, that's it, local variables, parameters and return values Small Basic style. I hope you found it helpful. Please send me your comments and/or suggestions and, if you found this useful, please share it with your friends.

No comments:

Post a Comment