Day 6

This is the Day 6 page for computer programming course 101, an introduction to computer programming. Day 6 is the second of two parts on the topic of functions.

Below are the topics and course materials we are learning today.

Procedure and Function Arguments

Previously we discussed that routines can have zero or more arguments. Arguments to a routine are specified by the caller through an opening parenthesis, a list of values separated by zero or more commas, and a closing parenthesis. For example:
function StringToInteger(S: string): Integer;
We have one argument to the StringToInteger function. But suppose the value passed to the function is not a valid integer. What could be done to tell us if the value held by S is not a valid integer?

Arguments by Reference

We could change the declaration of the function to use an argument by reference like so.
function StringToInteger(S: string; var Value: Integer): Boolean;
Then would could write something like this in our program.
var
  I: Integer;
  S: string;
begin
  I := 0;
  repeat
    WriteLn('Enter a number');
    ReadLn(S);
  until StringToInteger(S, I);
  WriteLn('You provided the number value ', I);
end.
So why does this work, and what does var Value: Integer mean? The var keyword means we are passing an argument by reference.

An argument passed by reference allows us to modify a value passed to us. This effectively allows us to return return two items from a function. The number and the success. The number is is placed in var Value and the Boolean is placed in Result. The result then tells us if S contained a valid number.

Let's try this out. Here is our implementation of the StringToInteger function.
function StringToInteger(S: string; var Value: Integer): Boolean;
var
  Negative, Found: Boolean;
  I: Integer;
begin
  S := StrTrim(S);
  Negative := False;
  Found := False;
  Value := 0;
  for I := 1 to Length(S) do
  begin
    if (I = 1) and (S[1] = '-') then
    begin
      Negative := True;
      Continue;
    end;
    if S[I] in ['0'..'9'] then
    begin
      Found := True;
      Value := Value * 10 + Ord(S[I]) - Ord('0');
    end
    else
    begin
      Value := 0;
      Exit(False);
    end;
  end;
  if Negative then
    Value := -Value;
  Result := Found;
end;
Can you find the two places in the above function where a boolean value is returned from this function?

Default Argument Values

In our StringToInteger function what is Value set to if S does not contain a valid string representation of an integer?

What if we wanted to modify StringToInteger to contain a default value other than zero without rewriting out routine? We can do just that by using a default argument or optional argument. A default argument looks like this.
function StringToInteger(S: string; var Value: Integer; DefaultValue: Integer = 0): Boolean;
Default arguments can be added to any procedure or function, but since they are optional they must appear at the end of the argument list. Can you rewrite our StringToInteger to use a default argument?

Constant Arguments

If there were and opposite of arguments by reference it would be constant arguments. A constant argument is one that cannot be modified. If we were to examine our StringToInteger function does it look like the value held by S is modified?

If want to let the user know that the value held by an argument is not going to be modified, we can declare it as const. Consider this declaration of our function.
function StringToInteger(const S: string; var Value: Integer; DefaultValue: Integer = 0): Boolean;
Can you see what changed?

Constant arguments tell the compiler we are not going to modify an argument. It then can produce more optimized code by reusing a variable rather than making a copy of all the data in the event it is modified. A general rule is if you dealing with information that is larger than your CPU architecture, if you know it's not going to be modified mark it as const.

Overloading Procedures and Functions

Often you may encounter times when you want to write a procedure or function and having it operate of different types. Consider for example sorting numbers for least to most or sorting a list of words alphabetically. To do this you would want to examine two numbers or two letters to determine which one is of less value.
function Min(A, B: Integer): Integer;
function Min(const A, B: string): string;
If you try to compile the above two functions you will receive an error. The error will tell you that you cannot have two functions to share the same name. Rather than forcing you the create many different names for routines that essentially perform similar tasks, you can tell the compiler you want to create multiple routines with the same name. To do this you add the overload directive to the end of your routine declaration like so.
function Min(A, B: Integer): Integer; overload;
function Min(const A, B: string): string; overload;
This tells the compiler we want to define the routine more than once with the same name, but each we declare it we use a different argument list. The argument lists must differ at least in one of its elements in type.

Let's write a few versions of both a Min and Max function.

Organizing Your Work

Have you noticed how we are writing functions and copying them around in files? Do you think there might be a better way to organize the functions we've been writing?

Well there is a better way to organize our work, and they're called units.

Making Our First Unit

The instructor shows the student how to create a new unit file.

Units are individual source code files that hold types, routines, variables, and constants which can be reused in other parts of our program. Let's use our new unit to hold our existing routines so far.
Min
Max
StrHash
StrTrim
StrToInt
IntToBinary
IntToHex
IntToStr
And let's add a few more new functions.
function ToUpper(C: Char): Char; overload;
function ToUpper(const S: string): string; overload;
function ToLower(C: Char): Char;
function ToLower(const S: string): string; overload;
function StrOf(C: Char; Count: Integer): string;
function PadLeft(const S: string; Count: Integer): string;
function PadRight(const S: string; Count: Integer): string;
procedure Swap(var A, B: Integer); overload;
procedure Swap(var A, B: Char); overload;
procedure Swap(var A, B: string); overload;

Unit Example: Word List

The instructor walks the student through the word list unit and a supporting application. We use logic to check the validity of arbitrary words.

Homework

There is no homework for day 6.

See also