{ «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«» «» «» «» TUTORIAL EIGHTEEN «» «» «» «» by «» «» «» «» Anthony Peck «» «» «» «» «» «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»   43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 It's your function to address these parameters... All the guff about procedures having their own variables and/or constants we saw in Tutes11-15 also applies to functions. Functions may also call other functions and/or procedures. All discussions of scope we've covered previously also applies to functions. To illustrate this, let's try a more complex program. This one will incorporate a few ideas mentioned in previous tutorials, as well some extra stuff on error checking. Let's imagine we want to write a program which finds the economy of a car over a journey (or several journeys). Nearly all cars on the road today have an odometer reading in kilometres. Similarly, petrol is dispensed by the litre. Despite the powers that be trying to convince us that we need to measure economy in litres per 100 kms, many people prefer the old miles per gallon measurement. Our program will need to get the numbers for litres and kilometres, check for errors in the data (e.g. negative numbers), calculate the economy for both metric and imperial users, and finally display the results. Here's a rough draft...    getnumber(litres);       getnumber(kilometres);       metric(metric or imperial);       calculate economy;       display result;        The procedure GETNUMBER could incorporate explicit error checking. Previously, a negative number entered has been simply converted. The user never knew that a mistake of data entry was made. This time, we'll use a REPEAT loop until the correct response is entered. We can use similar error checking for getting the conversion option. Let's give this a whirl... } Program MDTute18 (Input,Output); { This program finds the economy of a car, given the number of kilometres travelled and the litres of petrol used Author : A N Peck Date : 3rd January 1995 Procedures used: Title - makes a nice little title appear! Functions used: Getnumber - prompts user for a number Metric - prompts user for choice of conversion } const tab = ' '; var litres,kms: real; { ---------------------------------------------------------- } Procedure Title; { Prints up a nice title on the screen } begin writeln; writeln(tab,'Economy Calculator'); writeln(tab,'------------------'); writeln; write(tab,'This program will calculate the economy of a car '); writeln('given the kilometres'); { ^ | |_ I've split this up just to make the code look nice... } writeln; writeln(tab,'travelled, and the litres of petrol used!'); writeln; end; { Title } { ---------------------------------------------------------- } Function Metric: boolean; { ^ | |_ Another boolean function! } { Prompts user for a response to a question } var which_conversion: byte; { ^ | |_ This function has it's own variable. This is a local variable and would not be understood if used outside this function (a bit like freemasonry) } begin Metric := FALSE; { ^ | |_ It's a good idea to set your flag first, then we all know what we're talking about (if you find out then let me know because I'm making it up as I go along!) } repeat { ^ | |_ Remember that a REPEAT loop executes at least once. We could've used a WHILE loop, but it would need to be "primed"... } begin writeln(tab,'1: Metric '); writeln; writeln(tab,'2: Imperial'); writeln; write(tab,'Enter selection: '); readln(which_conversion); writeln; end; until (which_conversion = 1) or (which_conversion = 2); { ^ | |_ If the user enters anything other than a "1" or "2", this condition will not be met, and the loop will execute again. This type of error checking ensures that the user is aware of the mistake. You could also include some unsavoury remark regarding their inability to follow basic instructions! } Metric := (which_conversion = 1); { ^ | |_ Yikes! What the furry firetruck is this? With boolean evaluation, you can set the TRUE/FALSE flag using this wacky looking format. Alternatively you could code...    If which_conversion = 1 then Metric := TRUE;        } end; { Conversion } { ---------------------------------------------------------- } Procedure Getnumber (whichone: string; Var userchoice: real); { Prompts user for a number } begin repeat begin write(tab,'Please enter the ',whichone,': '); readln(userchoice); writeln; end; until userchoice > 0; { ^ | |_ Once again we see a REPEAT loop which won't allow the user to enter in silly values (negative numbers or zero). } end; { Getnumber } { ---------------------------------------------------------- } { ---------------------------------------------------------- } begin { Main Program } kms := 0.00; litres := 0.00; Title; Getnumber('kilometres travelled',kms); Getnumber('litres of petrol used',litres); If metric then { ^ | |_ Call function METRIC and test if result is true. All quite compact and easy to read. For it's next trick, Pascal will wash all your dishes and brush the dog. } begin write(tab,'The metric economy is',100*(litres/kms):0:2); writeln(' litres per 100 kms'); end else { ^ | |_ If METRIC isn't true the only alternative is FALSE, which means the user must have entered in a "2", requesting an imperial calculation. } begin litres := litres/4.541; kms := kms*0.62137; { ^ | |_ A couple of rough conversions. } write(tab,'The imperial economy is',kms/litres:0:2); { ^ | These have now been effectively _| converted to miles and gallons. We keep the same variable names only in an attempt to confuse the meek. } writeln(' miles per gallon'); end; writeln; end. { Main Program } { ---------------------------------------------------------- } { Well, wasn't that nice. I actually started off with the intention of calling all sorts of functions from other functions, doing handstands in the middle of procedure calls and generally hamming it up on the modular coding front. Looking back at my first drafts, I realised it would be better if I just stuck to a simple program for doing what amounts to a simple task. If you've got any complaints about that, write to my complaints department c/o The South Pole. You can find it on the map below! }                                           «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«» «» «» «» Globulus rotatus «» «» «» «»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«»«» 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43 !¡ 43   }