Programmation Bases

Hello World! Here is Switch. Today, I will introduce bases of programming through various languages. I will try my best to explain how to write clean simple code in different way and how you can pass from a language to another.

In this article, I will use: C, OCaml, Golang, Python and a custom pseudo code to go through some basic problems we can find.

Basic code organisation

When learning how to code, you will often start of by putting everything in a single place, providing a correct but heavy solution. For example, you would probably do something like:

print("Hello World!")
print("Hello Switch!")
pint("*")
pint("**")
pint("***")
pint("****")

When asked to display:
Hello World!
Hello Switch!
*
**
***
****

And it works.

Though this example is a bit exaggerated, it is a clear representation of what juniors will have hard time to balance: code separation.

Programming languages offers you various way to associate values to names and define repetitive process as function. A simple way to clarify the previous example is to define a function to say hello

function Hello(to):
  message = "Hello" + to + "!"
  print(message)

To avoid the repetition of the print line with Hello ! + name.

They also provide solution for repetitive tasks. Mosts current programming languages integrate for and while loop or accept recursive function (a function who call itself). So, to display the * triangle, we could propose something like

stars = ""
for i from 0 to 4 do:
    stars = stars + "*"
    print(stars)

The first thing you will find hard is to know if you should or not split a code block into a dedicated function or if a process has enough repetition to loop over it.

There are a lot of way to organise a code base, each one having its strong and weak points. In this blog, I will mainly use a basic module separation for small projects (regrouping related feature in a single module without specific rules) and Clean Architecture for heavier code base (clean separation between project objectives, data management, transport to the user and functional block).

Now, let’s try to solve some basic problems.

Data swap (C – OCaml)

First, we will produce algorithms to allow data swapping between two variables. The simplest solution for this is to use a third variable as tampon to store initial data, giving something like:

a = 125
b = "trust"
c = b
b = a
a = c

But what if I wished to make the same swap without relying on a secondary variable ?

In order to simplify the reflexion, we will consider swapping integer only. If I have a variable A set to 5 and a variable B set to 2, how can I make A become 2 and B 5 without relying on a temporary storage. A simple solution is to use a protective operation between two values witch stores a composed value from initials and will allow to separate them at the end. Let’s say that we add A to B, B is then 7 and A is till 2. When I remove A from B in A, I will have A = B – A = 7 – 2 = 5, witch is the initial value of B. Then I can remove A from B to retrieve A, cause: A = A + B – B and B = A + B – A, storing A + B – A in A and A + B – B in B will result in a swap.

a = 7
b = 2
b = a + b
a = b - a
b = b - a

Now let’s move to code.
First, we will implement it using C. C is one a first hight level langage ever, appearing in 1972 and is still heavily used in embedded system (car electronics for example). Lot of langages created since then are based on it.

It is a static strongly typed langage, meaning you have to specify the type of any variable you create and function return value and types cannot overlaps (you cannot add an integer with a character chain). C defines

#include LIB; // include a library to use its functions

TYPE NAME(T1 P1, T2 P2, ...) {} // declare a function named NAME returning type TYPE having parameters P1 of type T1 AND P2 of type T2

TYPE NAME; // declare a variable NAME of type TYPE

return SMTG; // stop function and make it returns SMTG

funcName(P1,P2,...); // Make a function call to funcName with parameters

Every C program has to provide a main function returning a type int. This function can have either a void argument (meaning nothing as to be provided) or a couple of parameters: (int argc, char *argv[]). This function represents your feature and is the only entry point to it. The int returned is used to indicate if errors occurs while computing. 0 means every thing was correct, any other states are errors.

Let’s define the swap feature as a single main block. We will need to defined numerical or string variables (defined here means they have a specified value) and a process to swap them.

int main(void) {
  int a, b; // declare two integer variables

  a = 2;
  b = 5;

  printf("First value is: %d and second value %d\n", a, b); // show before swap
  b = a + b; // get sum of A and B
  a = b - a; // A + B - A = B -> A is now B
  b = b - a; // A + B - B = A -> as A is B, and B is A+B, B is now A
  printf("First value is now: %d and second value %d\n", a, b); // swap done

  return 0; // return 0 cause all went well :)
}

Now we have our main code to swap. Let’s isolate swap in a function:

void swap(int a, int b) {
  b = a + b; // get sum of A and B
  a = b - a; // A + B - A = B -> A is now B
  b = b - a; // A + B - B = A -> as A is B, and B is A+B, B is now A
  printf("First value is now: %d and second value %d", a, b); // swap done
}

We defined a swap method with two integer arguments witch will swap provided value then print swap result.

Then let’s allow user to provide integer to swap. We have two options for this. Either let the user define the values on the fly, or let him provide values when running the program. The first solution relies on stdio library witch allow writing and reading standard entries, the second solution uses C args (argc, argv couple) from main function.

Following code will expect user to pass two integers arguments to program. Then we just have to call our swap method to have the job done.

int main(int argc, char *argv[]) {
  int a, b;

  if (argc != 2) { // check that we received 2 arguments
    printf("Swap expect 2 arguments, %d received!", argc)
    return 1 // return 1 cause we received an unexpected number of arguments witch is an error
  }

  a = atoi(argv[0])
  b = atoi(argv[1])

To let the user provide input its value while running the program, we can define a simple method witch will prompt him to enter a value then return it to main code.

int getInt(void) {
  int a;
  printf("Enter an integer:");
  scanf("%d", &a); // scan user input and store it in a variable. The & is required      here to let scan method modify a values (pointer concept)
  return a;
}

Now, I would like to provide this swap method from another language. What should I keep, what should I check to ensure it still works.

First, I always can reuse the same algorithm in any language. How it is implemented will change depending on the syntax of the language but the concept behind it can be conserved. Then I have to know how the language allows me to do tasks like converting value or recovering user inputs. Most programming language integrates solution for basic tasks like those but not all do. Then I can adapt my code to the new target. Let’s do it with swap and move it to OCaml.

OCaml is a language derived from C but its syntax is quite different. It is still a strongly typed langage but it use dynamic typing instead of static (you can force types using specific file to describe expected types but if you do not, OCaml will determine the best choice).

Now, let’s adapt our C swap to OCaml. While C required a main function, OCaml does not. It will execute the file you provide to him as it is defined. So we just have to create a file witch declare swap function then call it.

let swap a b = 
  let b = a + b in 
  let a = b - a in 
  let b = b - a in 
  (a, b);;

swap 2 5;;

Here, we are doing exactly the same process than C version, but instead of printing the result, we are returning it. Using let … in, we redefined variables a and b to new value, then we define the couple (a, b) as resulting expressing for swap method. So when calling swap 2 5, we obtain the couple 5, 2 as a result.

You can find code for other langages directly on github: https://github.com/switchelven/programming-bases as I will not detail them as the adaptions are equivalent to C to OCaml conversion. So let’s move on to the next problem.

Min and max (Go)

This time, we would like to find the maximum or minimum from a list of value. With this method, the list 2,4,1,3,5,7,9 should provide 1 when computing min and 9 for max. Once again, there are multiple may to do so. The simplest one is to compare each element one by one until we find min and max. Another would be to sort he list then take the first and last element. We can also think of multiple solution for comparison.

Let’s start with the comparison. Of course, most languages will provide a direct comparison operators. And we will mostly use those operators as its clearer. But as an exercice, I would like to find a way to get min and max value directly from a calcul instead of unknown methods provided by the languages. Theoretically, we can use the fact that A + B + A – B= 2A and absolute values. How ? We know that |A-B| = A-B when A > B and |A-B| = B-A when A < B. From this, we can say that A+B+|A-B| will give 2A if A > B and 2B if B > A. Then using this result, we can also deduce than A+B-|A-B| will give 2A if A < B and 2B if B < A. Then our computation for min and max can be express like:

function max(a, b) {
  return (a+b+|a-b|)/2
}

function min(a, b) {
  return (a+b-|a-b|)/2
}

Then let’s implement it. This time, I will provide you a Go implementation you can adapt in other langages.


func Min(a int, b int) uint {
   return uint(a+b-abs(a-b)) / 2
}

func Max(a int, b int) uint {
   return uint(a+b+abs(a-b)) / 2
}

func main() {
   fmt.Println("Min of", 135, 209, "is", Min(135, 209))
   fmt.Println("Max of", 178, 179, "is", Max(178, 179))
}

You will notice that Min and Max function returns an uint instead of an integer. I choose this type to hint that this algorithm does not work well with negative numbers. Using an unsigned integer indicates Min and Max will never return negative numbers correctly. If you test the method on signed integer, you will see that this method works correctly for positive integer or differently signed integer. If both integers are negative, Min will return the max of the two while Max will return the minimal due to the absolute difference being computed.

Now, we have to apply this method to a list of value. I talked about two different way to find the minimal and maximal value of a list. Comparing all element agains them selves is better than sorting the list when the list is randomly sorted. If the list is quite sorted, sorting it will be faster. As we cannot determine sorting of a list at computing time, we will have to choose depending on precondition. We can ensures those precondition when relying on internal inputs or specific structure. We could define an always sorted list where appending values will add it directly to its correctly sorted place.

Assuming that the list as random sorting, the simplest implementation to get minimal and maximal value existing in an integer list in Go is

func MinMaxList(intList []int) (min uint, max uint) {
    // Set default value if slice is empty
    min = 0
    max = 0

    // Search for min and max in slice
    for i, x := range intList {
        // Set max and min on list fist element. 
        if i == 0 { // i is the index of element. Go starts indexing slices at 0
            max = x
            min = x
            continue
        }

        // Check if current min/max are still min or max comparing to current value
        max = Max(int(max), x)
        min = Min(int(min), x)
    }

    return // return computed min, max. The empty return in go will automatically returns named return parameters
}

Pow (Python, OCaml)

Now, let’s implement a pow method. Pow methods compute number power, a power is the repetition of multiplication (pow(2,3)=2*2*2=8). You already know a way to repeat a define number of time a single operation using for loop. This will give a pseudo code like:

function pow(a, b) {
  res = 1 // pow(number, 0) = 1
  for _ from 0 to b do:
    res = a * res
  return res
}

Another way to do so is to use a recursive function. Recursive function are function who defined simple known cases (globally called exit cases). They are known steps to the function where we exactly know the result. For pow method, we keep a single exit case with is (pow(n,0)=1). Then we have to find a method to go from any cases to those exit cases. Here, we can state that (pow(a, n)=a*pow(a, n-1)). So our recursive function will be expressed as:

function pow(a, n) {
  if n == 0 {
    return 1
  }
  return a * pow(a, n-1)
}

Recursive function are powerful but you need to be aware of their space complexity (the required memory to run them). If we decompose the pow function for pow(10,4), we have the following process:

call pow(10, 4):
pow(10,4) = 10 * pow(10,3)
  call pow(10, 3):
  pow(10,3) = 10 * pow(10,2)
    call pow(10,2):
    pow(10,2) = 1O * pow(10,1)
      call pow(10,1):
      pow(10,1) = 10 * pow(10,0)
        call pow(10,0):
        pow(10,0) = 1
        return 1
     pow(10,1)=10 * pow(10, 0) = 10 * 1 = 10
     return 10
   pow(10,2) = 10*pow(10,1) = 10 * 10 = 100
   return 100
  pow(10,3) = 10 * pow(10,2) = 10 * 100 = 1000
  return 1000
pow(10, 4) = 10 * pow(10,3) = 10 * 1000 = 10000
return 10000

We see that each recursive call stores an operation while waiting for next step to be computed. When next state is computed, it executes is own stored operation before returning. Basic errors when dealing with recursive function are incorrect simplification step. Simplification steps are steps that execute a partial operation to approach the basic steps (they are the steps doing recursive calls). If your simplification does not help to move to single case, you will never reach them and will not be able to exit your method, leading to stack overflow errors. Another common mistakes is to incorrectly compute result. You correctly reach your exits cases but the result is empty or invalid cause the method to simplify is not correctly implemented. When mastered, recursive method helps to cleanly defines some complex method. Now, let’s implement those two methods. I could present it in a single langage, but I will present you the Python implementation for the loop and OCaml way to implements recursive function.

def pow(a, n):
    res = 1
    for _ in range(0, n):
        res = res * a
    return res

if __name__ == "__main__":
    pow(3,10)
let rec pow a n = 
  match n with
  | 0 -> 1
  | _ -> a * pow a (n-1);;

pow 3 10;;

Pseudo code definition

I will define the following keys when using pseudo code:

X = Value -> stores Value into variable X allowing it to be called through X directly in the code (ex: stars = "*" will allow you to recover * character as stars in the next lines).

print(SOMETHING) -> display SOMETHING to user.

+ -> is a basic addition on numbers, a concatenation on others (ex: 1 + 4 = 5, "to"+"to"= "toto").

function Name(a, b, ...) -> define a function as Name expecting values for a, b, ... Provided value will be known as it was named in function definition.

for X from A to B do -> run proposed steps for each value from A to B known as X.

OCaml code definition

Ocaml was introduced in 1996 by french institute INRIA. It is initially designed to help with mathematical proofs and a singular syntax in the programming world.

open LIB;; (* include a library to use its functions *)

let NAME  P1 P2 = (* declare a function named NAME having parameters P1 and P2 *)
let NAME = VAL;; (* declare a variable NAME having value VAL *)
let rec NAME P1 P2 = (* declare a recursive function named NAME having parameters P1 and P2 *)

funcName(P1 P2 ...);; (* Make a function call to funcName with parameter *)

match (P1, P2, ...) with (* match P1, P2, ... with values)
| A, B, ... ->           (* P1=1, P2=B, ... then execute *)
| _, C, ... ->           (* P1 is any, P2=C, ... then execute *) 

Go code definition

Go is a Google developed langage witch appear in 2009. It is a classic strongly static type langage.

import MODULE // import module MODULE

var NAME TYPE // declare a variable named NAME of type TYPE

func NAME(P1 T1, P2 T2) (RT1, RT2) // define a function NAME having parameters P1 of type T1 and P2 of type T2 returning a couple of type RT1, RT2

Python code definition

Python is a complete langage aiming for simplicity and human comprehension. It was first released in 1980 and is weakly typed. It is very adaptative and is syntax is quite permissive witch make it look like a good langage to start but its quite the opposite. As the langage by itself does not provide any safeguard around common mistake like type incorrect inference and such, you encounter lots of unexpected issue while using it if you are new to programming. None the less, its still is a very good langage largely used and the default langage for data science.

import MODULE // import module
import MODULE from path.to.file // import specific module from file/module

def FUNC(P1, P2): // define function FUNC having parameters P1 and P2

A = VAL // defines a variable A set to VAL

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

en_US