Tutorial 10

✏️

Functions & Procedures - Custom

2210 O-Level


The previous tutorial looked at the built-in Cambridge modules/sub-routines (functions or procedures) - in this tutorial, we'll look at how to create and call (use) our own

A recap, the difference between a function and procedure is outlined below:

  • Functions will return a value that can be used to assign, in a calculation, a condition, output statement etc
  • Procedures won't return a value - we can output data inside the procedure, but the procedure itself won't evaluate to an answer

The benefits of creating functions and procedures include:

  • Organisation - keeps code organised into small, logical blocks
  • Reusability - don't have to copy and paste same functionality over and over
  • Flexibility - if we need to modify behaviour, we only need to change once inside the module
  • Testing - easy to test individual modules to ensure they work
  • Parameterisation - can use the same module with different parameters to achieve different behaviour

1

FUNCTIONs

Each time we declare a function, we need:

  • FUNCTION & ENDFUNCTION keywords
  • An identifier (function name)
  • [optional] A list of parameters
  • A return data type
  • A return statement for every code path

A simple example is shown below that takes in an integer parameter, then returns whether it is a lucky number, according to some superstition:

Note: when specifying the return type in the function header, we use the keyword RETURNS, while when actually returning a value, we use RETURN

OUTPUT IsLuckyNumber(7) OUTPUT IsLuckyNumber(8) FUNCTION IsLuckyNumber(num : INTEGER) RETURNS BOOLEAN IF num = 7 OR num = 4 THEN RETURN TRUE ENDIF RETURN FALSE ENDFUNCTION

Note: the following example would be invalid - since not all situations (code paths) result in a value being returned

OUTPUT IsLuckyNumber(7) OUTPUT IsLuckyNumber(8) FUNCTION IsLuckyNumber(num : INTEGER) RETURNS BOOLEAN IF num = 7 OR num = 4 THEN RETURN TRUE ENDIF //we need to return something if the number isn't 7 or 4 ENDFUNCTION

Note: the order of execution demonstrated via these OUTPUT statements - when we return from a function, we leave it and execution continues from the position the function was called from - this is why the OUTPUT "Leaving Function" statement will never execute

OUTPUT "-- Before Try 7-- " OUTPUT IsLuckyNumber(7) OUTPUT "-- Before Try 8 ---" OUTPUT IsLuckyNumber(8) OUTPUT "--- Finished ---" FUNCTION IsLuckyNumber(num : INTEGER) RETURNS BOOLEAN OUTPUT "In Function" IF num = 7 OR num = 4 THEN RETURN TRUE ENDIF RETURN FALSE OUTPUT "Leaving Function" // will never execute, since we have already returned ENDFUNCTION

2

PROCEDUREs

Declaring a procedure requires less code than a function, since we don't have to return anything - we simply need:

  • PROCEDURE & ENDPROCEDURE keywords
  • An identifier (procedure name)
  • [optional] A list of parameters

Note: in order to call (use) a procedure, we require the CALL keyword

CALL Welcome("Alice") CALL Welcome("Bob") PROCEDURE Welcome(name : STRING) OUTPUT "Welcome to pseudocode.pro, ", name ENDPROCEDURE

3

Multiple Parameters

For either functions or procedures, we can either write each parameter and its data type individually, or if we have consecutive parameters of the same type, we can simply separate them with a comma - like the "name" and "email" parameters below:

CALL DisplayDetails("Claire", "claire123@proton.me", 25, TRUE) PROCEDURE DisplayDetails(name, email : STRING, age : INTEGER, paid : BOOLEAN) OUTPUT name, " is ", age, " years old, has the email address ", email, " and their paid status is ", paid ENDPROCEDURE

4

Triangle

Create a procedure that can output a right-angled triangle to a given depth - for example, if the depth was 4, the result would be:

Note: this question requires the string concatenation operator & - while this is technically an AS operator, it is simple enough to learn and allows us to complete this challenge - it simply joins two strings. For example "pseudocode" & "pro" would result in the combined string "pseudocodepro"

CALL DrawTriangle(10) PROCEDURE DrawTriangle(depth: INTEGER) DECLARE line : STRING DECLARE numStarsForThisLine, starNum : INTEGER FOR numStarsForThisLine ← 1 TO depth line ← "" FOR starNum ← 1 TO numStarsForThisLine line ← line & '*' NEXT starNum OUTPUT line NEXT numStarsForThisLine ENDPROCEDURE

5

Hash Length

There are various online tools that can take a hash digest (string), then based on its value, try to predict the hashing algorithm that we used - one simple approach is by the length, since most hashing algorithms produced fixed-length hashes

Create a function that takes a string hash digest and returns the name of the possible hashing algorithm used

The data below shows the hashing algorithm and length (in characters) of the digest it produces:

  • md5: 32
  • sha256: 64
  • sha512: 128

If the length doesn't match one of these value, then [UNKNOWN] should be returned

You can use this site to hash various values to use as arguments for your function - e.g. "hello world" hashes to "5eb63bbbe01eeed093cb22bb8f5acdc3"

OUTPUT PredictHashAlgorithm("5eb63bbbe01eeed093cb22bb8f5acdc3") OUTPUT PredictHashAlgorithm("abc") FUNCTION PredictHashAlgorithm(digest : STRING) RETURNS STRING CASE OF LENGTH(digest) 32: RETURN "md5" 64: RETURN "sha256" 128: RETURN "sha512" OTHERWISE: RETURN "[UNKNOWN]" ENDCASE ENDFUNCTION

6

Is Even

Create a function that returns a Boolean value corresponding to whether an integer parameter is even or not

OUTPUT IsEven(4) OUTPUT IsEven(5) FUNCTION IsEven(num : INTEGER) RETURNS BOOLEAN RETURN MOD(num, 2) = 0 ENDFUNCTION

7

Is Prime

Create a function that returns a Boolean value corresponding to whether an integer parameter is prime or not

Use this function in a loop to output all the primes between 1 and 1000

DECLARE n : INTEGER FOR n ← 1 TO 1000 IF IsPrime(n) THEN OUTPUT n ENDIF NEXT n FUNCTION IsPrime(num : INTEGER) RETURNS BOOLEAN DECLARE max, index : INTEGER max ← DIV(num, 2) IF num <= 1 THEN RETURN FALSE ENDIF FOR index ← 2 TO max IF MOD(num, index) = 0 THEN RETURN FALSE ENDIF NEXT index RETURN TRUE ENDFUNCTION

8

Swap Case

Create a function that takes a string then swaps the case of each character - e.g. "psEudoCOdE" should become "PSeUDOcoDe"

OUTPUT SwapCase("ascii UNICODE") FUNCTION SwapCase(orig : STRING) RETURNS STRING DECLARE newStr : STRING DECLARE index : INTEGER DECLARE currentChar : CHAR newStr ← "" FOR index ← 1 TO LENGTH(orig) currentChar ← SUBSTRING(orig, index, 1) IF currentChar >= 'a' AND currentChar <= 'z' THEN newStr ← newStr & UCASE(currentChar) ELSE IF currentChar >= 'A' AND currentChar <= 'Z' THEN newStr ← newStr & LCASE(currentChar) ELSE newStr ← newStr & currentChar ENDIF ENDIF NEXT index RETURN newStr ENDFUNCTION

9

Times Table

Create a procedure that outputs the times table of a given number from a start to ending multiplier - for example CALL DisplayTimesTable(6, 10, 20) would output:

CALL DisplayTimesTable(6, 10, 20) PROCEDURE DisplayTimesTable(timesTable, start, end : INTEGER) DECLARE index : INTEGER FOR index ← start TO end OUTPUT index, " x ", timesTable, " = ", (index * timesTable) NEXT index ENDPROCEDURE

10

Absolute Value

Create a function that takes a number then returns its absolute value

OUTPUT abs(-5) OUTPUT abs(6) FUNCTION abs(num : REAL) RETURNS REAL IF num >= 0 THEN RETURN num ELSE RETURN -num ENDIF ENDFUNCTION

11

Factorial

Create a function that can return the factorial of a given number - i.e. factorial of 5 is 5 * 4 * 3 * 2 * 1 = 120

OUTPUT factorial(99) FUNCTION factorial(max : INTEGER) RETURNS INTEGER DECLARE num, total : INTEGER total ← 1 FOR num ← max TO 1 STEP -1 total ← total * num NEXT num RETURN total ENDFUNCTION

12

Distance from Integer

Create a procedure that generates a random number between 1-10 then outputs the closest integer and how close it is to the nearest integer - e.g. 6.25 has a distance of 0.25 from 6, while 7.9 has a distance of 0.1 from 8

CALL DistanceToInt() PROCEDURE DistanceToInt() DECLARE randNum : REAL DECLARE nearestInt : INTEGER randNum ← 1 + (RANDOM() * 9) OUTPUT "Number: ", randNum nearestInt ← ROUND(randNum, 0) OUTPUT "Nearest Int: ", nearestInt IF randNum >= nearestInt THEN OUTPUT "Distance: ", (randNum - nearestInt) ELSE OUTPUT "Distance: ", (nearestInt - randNum) ENDIF ENDPROCEDURE