Data structure: Chained List

Hello World! Here is Switch. Having introduce the bases of programming, it is time to go a bit deeper. This post will start a serie about data structure. Data structure defines solution to manage data set in a program and using the correct structure will greatly improve code performance. Also, a good structure will simplify the implementation of problem resolution.

As a first post around data structure, I will introduce the basic Chained List structure.

Structure description

A chain list build upon a single entry point witch represent the Head of the list. The head stores a value and a reference (pointer) to the next listed elements. It has no index notion and is a first in, last out structure. It means that you will neither have a direct access to a known element of the list without depilating all heads before the elements and the first element to be added will be retrieved last.

Graphical representation of list: [9,1,12]

When defining a list, we have to provide user with basic function to manipulate it. We also like to define more advanced powerful tools.

Essentials feature to provide is a Prepend method to add element to a list. You also have to provide a Head and a Tail function to retrieve the first element and queue of current list head.

For advanced tools, I like to provide a Sort method witch will allow you to reorder list elements and a Map function. The Map function allows you to apply a method to each element composing the list. If I call Map with a times two function on the [9,1,12] list, it should return me the [18,2,24] list.

Pseudo code defintion

Now, let’s propose a pseudo code definition of the list structure. I will introduce a new keywords to our pseudo code: define NAME { Properties list }. It will create a structure named NAME containing specific values. I can associate methods to this structure using func NAME(Variable).Method notation and properties listed in the structure can be accessed through NAME.Property.

Let’s define the basic structure and methods.

define List {
  Head any
  Tail List
}

emptyList = List{} // I expect emptyList to be a global constant.

func NewList() List {
   return emptyList
}

func List(l).Prepend(element any) List {
   return List{
        Head<-element
        Tail<-l
   }
}

func List(l).Pop() any, List {
    return l.Head, l.Tail
}

Our list structure keeps track of its head and tail by relying on an internal propertie Head and Tail. Head is any value you wish to add to the list and Tail the reference to next part. I define an emptyList constant so we can easily identify it. NewList create an empty list where you will be able to add elements. Prepend method takes the value you provide to it and build a new List structure using current List element as Tail. Finally, the Pop method will return you a couple containing the Head value of the list and the full Tail list.

Then let’s simply sort the list. I will propose the basic bubble sort implementation. To bubble sort a list, you need to sort its tail then add the head at the current place in the sorted list. Witch will give something like:

func List(l).SortedAdd(element any, comp function) List {
     if l == emptyList {
         return emptyList
     }

     if comp(element, l.Head) is True {
          return List{Head<-element, Tail<-l}
     }

     return List{Head<-l.Head,Tail<-l.Tail.SortedAdd(element, comp)}
}

func List(l).Sort(comp function) List {
     if l == emptyList {
          return l
     }
     
     sorted = l.Tail.Sort()
     return sorted.Add()
}

Finally, let’s define the Map method. Map will go through each Head element in List, apply provided method and build a new list element using this newly computed value and the application of Map to its Tail.

func List(l).Map(fn function) List {
     if l == emptyList {
         return emptyList
     }

     return List{Head<-fn(l.Head),Tail<-l.Tail.Map(fn)}
}

Now let’s code it in Go.

Test definition

We will start by defining a code process for our list. We know that we will create a List structure witch will contained a Head of type interface{} (interface is a neutral type in Go) and the Tail will contained a recursive call to List type. For this structure, we wish to define an Empty value and an asserter for emptiness. We also wish the constructor of list type to provide an Empty list. A first test would then be:
– When I create a new list
– I expect it to be an Empty list

func TestNewList(t *testing.T) {
   Convey("When I create a list", t, func() {
      newList := list.New()
      Convey("I expect it to be empty", func() {
         So(newList.Empty(), ShouldBeTrue)
      })
   })
}

Then we would like to add element to a list. After adding an element, I should ensure the updated list is not empty, as a Head value equal to provided data, and has a tail equals to initial list. The test protocol would be:
– Given I have an empty list
– When I add an element X
– List should not be Empty
– Head should equal X
– Tail should be empty


– Given I have a list L
– When I add an element X stored as newL
– newL should not be Empty
– newL Head should equal X
– newL Tail should equal L

Convey("Given I have ", t, func() {
   Convey("an Empty list", func() {
      l := list.New()
      Convey("When I add an element X", func() {
         newL := l.Prepend("X")

         So(newL.Empty(), ShouldBeFalse)
         So(newL.Head, ShouldEqual, "X")
         So(newL.Queue.Empty(), ShouldBeTrue)
      })
   })

   Convey("a list", func() {
      l := list.New().Prepend("X").Prepend("Y").Prepend("Z")
      Convey("When I add an element X", func() {
         newL := l.Prepend("A")

         So(newL.Empty(), ShouldBeFalse)
         So(newL.Head, ShouldEqual, "A")
         So(*newL.Queue, ShouldResemble, l)
      })
   })
})

Then we can define test protocol for Pop:
– Given an Empty list L
L.Pop() should return nil, EmptyList

– Given a [3,4,5] list L
– L.Pop() should return 3, [4,5] as H, L2
– L2.Pop() should return 4, [5]

Convey("Given", t, func() {
   Convey("an Empty list", func() {
      l := list.New()
      h, q := l.Pop()
      So(h, ShouldBeNil)
      So(q.Empty(), ShouldBeTrue)
   })

   Convey("a known list", func() {
      l := list.New().Prepend(5).Prepend(4)
      l2 := l.Prepend(3)
      h, q := l2.Pop()
      So(h, ShouldEqual, 3)
      So(q, ShouldResemble, l)
      h2, _ := q.Pop()
      So(h2, ShouldEqual, 4)
   })
})

Now, we should ensure Map function will behave.
– Given an Empty List L
– L.Map(func(e interface{}) {return e}) should return Empty List

– Given a single element list L = [“hello”]
– And a function addWorld witch add ” world!” to string interface
– When I call L.Map(addWorld)
– Then I should have [“hello world!”] list

– Given a list L = [“hello”, “my”, “new”]
– And a function addWorld witch add ” world!” to string interface
– When I call L.Map(addWorld)
– Then I should have [“hello world!”, “my world!”, “new world!”] list

func TestList_Map(t *testing.T) {
   Convey("Given ", t, func() {
      Convey("an Empty list", func() {
         l := list.New()
         Convey("when I apply Map function", func() {
            newL := l.Map(func(e interface{}) interface{} { return e })
            So(newL.Empty(), ShouldBeTrue)
         })
      })

      l := list.New()
      addWorld := func(e interface{}) interface{} { return e.(string) + " world!" }

      Convey("a single element list", func() {
         l = l.Prepend("hello")
         expectedL := list.New().Prepend("hello world!")
         Convey("when I apply Map function", func() {
            newL := l.Map(addWorld)
            So(*newL, ShouldResemble, expectedL)
         })
      })
      Convey("a  list", func() {
         l = l.Prepend("new").Prepend("my").Prepend("hello")
         expectedL := list.New().Prepend("new world!").Prepend("my world!").Prepend("hello world!")
         Convey("when I apply Map function", func() {
            newL := l.Map(addWorld)
            So(*newL, ShouldResemble, expectedL)
         })
      })
   })
}

Finally, we should safe the sort function. Again, sort function should not alter empty or single element list. Also, given a sorted list, the list should stay sorted and given a randomly ordered list.

func TestList_BullSort(t *testing.T) {
   Convey("Given a list", t, func() {
      tmpList := list.New().Prepend(1).Prepend(4).Prepend(6).Prepend(9).Prepend(3).Prepend(5).Prepend(2).Prepend(10)

      expectedSorted := list.New().
         Prepend(1).Prepend(2).Prepend(3).Prepend(4).Prepend(5).
         Prepend(6).Prepend(9).Prepend(10)

      l := &tmpList
      comp := func(a, b interface{}) bool {
         return a.(int) > b.(int)
      }

      Convey("empty or single element, should stay as his", func() {
      })

      Convey("not sorted, I should be able to sort it", func() {
func TestList_BullSort(t *testing.T) {
   Convey("Given a list", t, func() {
      tmpList := list.New().Prepend(1).Prepend(4).Prepend(6).Prepend(9).Prepend(3).Prepend(5).Prepend(2).Prepend(10)

      expectedSorted := list.New().
         Prepend(1).Prepend(2).Prepend(3).Prepend(4).Prepend(5).
         Prepend(6).Prepend(9).Prepend(10)

      l := &tmpList
      comp := func(a, b interface{}) bool {
         return a.(int) > b.(int)
      }

      Convey("empty or single element, should stay as his", func() {
         l := list.New()
         So(l.BullSort(comp), ShouldResemble, &l)

         l = list.New().Prepend(1)
         So(l.BullSort(comp), ShouldResemble, &l)
      })

      Convey("not sorted, I should be able to sort it", func() {
         l = l.BullSort(comp)
         So(*l, ShouldResemble, expectedSorted)
      })

      Convey("sorted, I should be able to sort it", func() {
         l = l.BullSort(comp)
         l = l.BullSort(comp)
         So(*l, ShouldResemble, expectedSorted)
      })
   })
}

Then, we just have to complete our code until test pass.

Implementation

package list

// List represents a simple chained list.
// Head provides the element
type List struct {
   Head interface{}
   Tail *List
}

// MapFunc abstracts Map method arguments type
type MapFunc func(element interface{}) interface{}

// New initialize an empty list
func New() List {
   return List{Tail: nil, Head: nil}
}

// Empty asserts list is an empty list.
func (l List) Empty() bool {
   return l.Head == nil && l.Tail == nil
}

// Prepend adds elements to list head.
func (l List) Prepend(elem interface{}) List {
   return List{
      Head: elem,
      Tail: &l,
   }
}

// Pop recovers head and queue
func (l List) Pop() (head interface{}, queue List) {
   if l.Empty() {
      return nil, l
   }
   return l.Head, *l.Tail
}

// Map applies a function to each element of a list
func (l *List) Map(fn MapFunc) *List {
   if l.Empty() {
      return l
   }

   return &List{
      Head: fn(l.Head),
      Tail: l.Tail.Map(fn),
   }
}

// AddSorted adds an element to sorted list at the right place.
// /!\ function will not work correctly on non sorted list.
func (l *List) AddSorted(e interface{}, comp func(interface{}, interface{}) bool) *List {
   if l.Empty() {
      return &List{Head: e, Tail: l}
   }

   if comp(e, l.Head) {
      return &List{Head: e, Tail: l}
   }

   return &List{Head: l.Head, Tail: l.Tail.AddSorted(e, comp)}
}

// BullSort sorts a list
func (l *List) BullSort(comp func(interface{}, interface{}) bool) *List {
   if l.Empty() {
      return l
   }

   sorted := l.Tail.BullSort(comp)

   return sorted.AddSorted(l.Head, comp)
}

You will find all code written in this article on github: https://github.com/switchelven/data-structure

That’s all folks. See you later.

Testing

Hello, here is Switch. Today, we will introduce program testing.

When we code, we make lots of fonctions witch have different impacts and can be broken for various reason (forgetting an assignment, wrong calcul, messed up pointers, global variables broken and so on). Those function are created to respect known objectives witch should be ensured by the methods. If we want to ensure our code respect the objectives, we need to test it.

Test solutions

At the beginning, you will be tempt to only relies on manual testing. You run your code until it works, adding debug points with logs and so on. The shortcoming of this method is quite obvious. When you code base is very light and you have a small number of features, you can easily cover all required test case by yourself. But it will be a nightmare when you start working on real applications. That leads to the apparition of automated test. Those test can be written on different level and has various usages. Though they run automatically, they have to be written by hand so they come with a time cost. If correctly managed, this cost can be nullify and it can make a team faster.

Testing is generally separated using levels:

  • Unit test: low level test witch call a single function and ensure it works as expected.
  • Integration test: low level test witch test a function and ensure it behaves as expected with external services. (To abstract Unit vs Integration, we can say a Unit test does not rely on external services while Integration does but they are the same kind of test, isolating a specific feature and ensuring it works).
  • Functional/API test: Global test relying on user callable endpoints. They ensure a feature provided to user will behave as it should.
  • End to End test: Test using the user interface directly. They ensure the final products correctly mapped function to user interface components.

There are a lot of test solutions build for each of those levels. Unit test are generally integrated directly with the langage (you use C code for C unit test, Go for Go, etc … ). For higher level test, frameworks usually try to abstract the langage behind and allows to express directly features to test (like gherkin witch let you define steps you will map in your own langage).

Test Driven Development

With the popularisation of testing and testing being more and more present and powerful, we have a new way to develop in sight. Instead of coding then write test to ensure code will not broke, we will first write a test then implement required code to make it pass.

When you are used to do testing after writing code, the step is hard to take. If you are in this case, you should try to write only thing you can know without knowing the implementation to create your test and divide test case in 3 steps: Initialize, Do, Ensure. This is a gage that was given to me while looking for solutions to enforce TDD so I also pass it to you.

If you are new to development, I would recommend getting used to it, and that’s what I made this article for.

So, how does TDD works and why should use it ?

There are mostly benefits to use TDD. It will helps you to minimalise the development. As you start by describing what your code must do, you will clarify your idea and fix the behaviour of your code before implementing. So when you implement, you know you can stop when the test pass.

You will write clearer test. As your test does not describe the implementation but the expectation, it will be clear to anyone with a minimal knowledge of code and your product.

Writing good tests

I do not own absolute knowledge on what a good test is. No one does. But some points seems to be proven useful

  1. Validate border cases, at least one global case, and known errors
  2. Mocks only relevant thing you own (a mock is a replacement for a part of the code where you enforce result to be return by code). If you use external services, you should use a mock server witch will return a known valid response taken from official server than mocking the client part to return what you would want.
  3. Clearly separate the initialisation, actions and expectation part.
  4. Can be used as documentation for developers. If you wrote a clear test correctly commented, any developer should understand how the code works and behave just from the test case.

That’s all for today. From then on, every article I will write including code part will describe test files first and be developed using TDD method. I hope you will adopt the same behaviour though I will never condemn those who do not goes through it.

Memory Usage

Hello World! Here is Switch. Today, we will quickly cover the notion of memory management in computer programs. I will cover notion from pointers to data scope and use program analysis to explain some points.

Introduction to memory management

This post doesn’t aim to cover the overall complexity of memory management witch requires to know how to access specific part of memory, choose between different memory providers and so on. It will instead focus on memory optimisation within a code by ensuring variables are correctly scoped avoid useless duplication.

There are lot of way to manage memory in a program. Nowadays, most langages use the notion of Garbage Collector to ensure memory taken by variables is released when it has no more usage but older langage such as C will require you to do it yourself.

Optimising memory usage through a program requires to correctly identifies the life cycle of values. When do I create it, witch function will use it and when will it be no more used. You also need to be aware of the weight of variables you are going to manipulate. Depending on your performance objectives, passing a full copy of variables to sub function can be a blunder.

Let’s look at this code:

a = 10
b = 15
c = a + b
d = a - b
e = c * d 

There are a lot to say. Though this code is quite simple, it is under optimised. Let’s say we cannot cumulate operation (I cannot directly write (a+b)*(a-b)). We could still save at least a variables.

Variables a and b are used to compute c and d so they need to be alive for c and d but e use c and d, not a and b so we don’t need a new variables here. It makes things more readable but take useless space. We could put c*d response to a or b to save a space. We can make the same analysis for d variables assignation. The last time a and b are used is to compute d. So we could save d value in a or b directly. This would give something like:

a = 10
b = 15
c = a + b
a = a - b
a = c * a 

This kind of optimisation is not required in modern programming langage cause compilers will do it for you, so it is better to keep a clear variable management that will help anyone to get what is going on.

Let’s move on to the main subject.

Variable scopes

The first point to correctly manage memory is to be aware of variable scope. The scope of a variable is the place she is define and the code part it will exist in. We mostly use local variable while coding. A local variable exists only where it is define and until the definer scope is destroyed.

As an example, in this code:

void anotherScope(void) {
  int c, a;
  c = 10;
  a = 4;

  printf("%d", a + c)
}

void scoped(void) {
  int a, b;
  a = 5;
  b = 4;
  
  anotherScope();
  printf("%d", a + b);
}

int main(void) {
  scoped();
  return 0;
}

The variables defined in anotherScope function exists only while it is running. The a variables in scoped and anotherScope are distinct and does not affect each others. This is due to scope isolation. A function call create a scope in witch variables will exists. Only variables defined by the function (entry parameters or locally defines) exists in this scope. If you need to share values between functions with a single name, you have to use global variables. In most langages, variables defined outside of function scope are considered global. Some can require the use of a global key word. If we redefined the previous code with a global a variable:

int a

void anotherScope(void) {
  int c;
  c = 10;
  a = 4;

  printf("%d", a + c)
}

void scoped(void) {
  int b;
  a = 5;
  b = 4;
  
  anotherScope();
  printf("%d", a + b);
}

int main(void) {
  scoped();
  return 0;
}

anotherScope and scoped change a global variable. This change the result. The initial result was

14
9

while it will give

14
8

when using a globally defines a.

Defining a global variables will help saving space when you need to share data between multiple functions around the code but can make it hard to debug issues happening when multiple part of the code modifies it in an unexpected order.

This code:

#include <stdio.h>
#include <stdlib.h>

int a

void anotherScope(void) {
  int c;
  c = 10;
  a = 4;

  printf("%d should be 14", a + c)
}

void scoped(void) {
  int b;
  b = 4;

  printf("%d should be 9", a + b);
}

int main(void) {
  a = 5;
  anotherScope();
  scoped();
  return 0;
}

Expect a comportement witch is not respected. Variable a is set to 5 in main and the scoped function expect it to stay at 5. But anotherScope set a to 4 without restoring the older value so when called before scoped, it affects the result and create a bug.

This comportment can lead to very tricky situation in larger code base where a global variables is used and altered by many functions.

Pointers

Another way to save memory is to use Pointers. A pointer is a direct reference to the memory. Instead of managing a value, we manage the place it is stored. An address is a light hexa object so it is quickly lighter than heavy struct. Using pointers instead of direct value will avoid copying data when manipulating the object in a specific function. As pointers are memory reference, you have to release it when you know it will not be used or you lost the tracking. Most of the modern langages does it by themselves relying on a garbage collector who keep track of pointers and variables and delete them when they are not used. But it can lead to some issue in langages where you have to release it by yourself like C.

Let’s manipulate some C pointers using the swap method implementation.

We have a swap method define like:

#include <stdio.h>
#include <stdlib.h>

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
}

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])

  swap(a, b)

  return 0
}

This code print the swapped values, but the swap method has no real use as it does nothing to provided values, nor does it provided the swapped couple. Let’s use pointers to modify the provided reference so swap will have a real use.

#include <stdio.h>
#include <stdlib.h>

// This method swap a and b values relying on
// a value computed swap
void swapValue(int *a, int *b) {
  *b = *a + *b;
  *a = *b - *a;
  *b = *b - *a;
}

// This method swap the address of a and b
void swapPointers(int **a, int **b) {
  int *c;
  c = *b;
  *b = *a;
  *a = c;
}

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

  if (argc != 3) { // 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[1]);
  b = atoi(argv[2]);
  pa = &a;
  pb = &b;

  swapValue(pa, pb);
  printf("First value is now: %d@%p and second value %d@%p\n", *pa, pa, *pb, pb); // swap done
  swapPointers(&pa, &pb);
  printf("First value is now: %d@%p and second value %d@%p\n", *pa, pa, *pb, pb); // swap done

  return 0;
}

The new swapValue method expect reference to an integer value (int *a indicates that a should be a pointer). It does not modifie the address but directly the value containing by those addresses. The other one, swapPointers, does not modify the values of the pointers but it inverse the pointers to a and pointers to b.

Hope those small example will help you. See you later 🙂

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

What is programming

Hello World. Here is Switch. Today, I propose a theoretical introduction to programming.

While lot of people see programming as quite a simple task, consisting of writing some phrases to make lot of things works, not a lot understand the true concepts behind programmation.

As you may know, a computer is just a simple logical calculator using only a suite of binary values (0 or 1). All those binary values are stored in limited spaces entity and each communication is done by aggregating and computing logical interaction between values.

History

Programming and computer sciences originated from automated devices and message encryption. From very simple encoded message or music sequencer to the advanced Enigma, mathematical theories and technologies behind the automation scene evolved, being more abstract and complex as time passed.

The first accepted publication of a computer program is attributed to Ada Lovelace in 1843. She proposed an algorithm computing sequence of Bernouilly numbers using the Analytical Engine.

It lifted the door to modern programming. The bases proposed by the Analytical Engine where improved times after time, allowing data storage, control panel and so on then moving from mechanical engines to electric computers.

Following the creation of controllable electronic computers, machine code langages appeared. They allowed represent algorithmic processes to machines in a very basic ways. Assembly langage are hard to read for human and requires a lot of knowledge in computer sciences to create optimised program.

This lead to the creation of High Level languages and the concept of compilation. Compilation is a way to translate human readable code to machine langage or a lower levelled one.

Programming ?

Programming is an application of mathematical theories to recreate known interaction. Though nowaday mathematical is less and less present in programmation as high level languages provides a human readable syntaxes to describes programs, advanced theorie like artificial intelligence are still heavily reliant on mathematical concepts.

Basically, an informatics program is just a suite of action required to compute a result, in other world, an algorithms. Anything you will do while manipulating a computer use an algorithmic process behind the hood.

So the job of a programmer is to describe the better fit algorithms to match user requirements and system limitation. You will not use the same algorithm to sort list depending on the machine it will be deployed on and the knowledge you have about list to sort.

Hope to be useful 🙂

Sources

Wikipedia: https://en.wikipedia.org/wiki/Computer_programming


More documents

Ada Lovelace: https://en.wikipedia.org/wiki/Ada_Lovelace
Bernouilly numbers: https://en.wikipedia.org/wiki/Bernoulli_number
Analytical Engine: https://en.wikipedia.org/wiki/Analytical_Engine

How did I fall into IT

Hello World. Here is Switch.

Today, I would like to tell you how I discover the IT world, and how I evolve into it until now.

This story begins when I was quite young (but also quite old for some).

First steps

I think that, at my time, they where two kind of thing in IT which young ones would like to discover. Either you wished to create a video game, either you wished to build you own website to share some of your life, project and other.

I was in secondary school when I first tried to build a website. Nothing great, I used a free solution to help me code using an editor like feature (as wordpress but offline), witch was called Nvu (later Kompozer).

I progressed by trial and error, checking on the internet what funny things I could try to build, or trying to find a way to display something I would like to. Step by step, I graduated for the editing vue to use mainly the coding part. Then I switched to true code editor (Coda was free at the time on Mac OS, then I evolved to Netscape and Sublime witch will be one of my main editors before VSCode and JetBrains suites).

Even though it was quite simple websites, and a lot of programmers would troll by saying pure HTML+CSS is not true programmation, it still build good base for my future growth. I already learned how to use existing resources, building your own from them. Also, learning how to build step by step a full project is quite a good foundation as you will then have a better understanding of tools creating them for you.

Algorithms discovery

The next step started in high school. A new world open to me using a calculator as bases. I don’t know for other country but in France, when you arrive in high school, you had to buy a complex calculator providing feature like graph representation and analysis, equation solving and, most important for me, a programmable one.

The langage was quite simple but it had all the bases of any imperative langage:

  • simple loop
  • variable declaration
  • assertions

So I started to implement the mathematical algorithms I learned, such as euclidian division, 2d degree equation solving, and so on. Through this process I cleaned most of beginners mistakes and learned to fell something was missing as I could not freely reuse existing programs in another one. I had to build each programs as an individual block. So I cleaned most of my inputs and outputs to easily chains programs when calling them and self discipline myself to reduce the possible entries. Also, I like to check a lot from the user entry. There are two way to manage them when providing function to safe entry (internal to company usage only by devs for example). You can assume that any one calling the function as to know how it should be called, then if an entry is invalid, it becomes the user fault as he/she did not correctly called the method. Or you can secure each called by checking any entry and ensuring it matched expected conditions. I like the second method more as I learned programming using langage who did not allow comments and did not provide on the fly documentation for methods while coding. Also, it ensures that the method can be called by any end user without the need to build a new security couch.

Learning in school

I decided to follow programming classes after high school. I entered preparatory classes to prepare for mathematics and physics colleges with competitive entrance examinations and choose computer science as a minor.

It was my first contact with a form a paradigm I still love, witch is functional programming. Learning it allowed me to clarify and widen my vision when building tools. A lot of methods to simplify problems, divide them, link them with mathematical theory was presented to me during those years. And it made me choose to become a Computer Science engineer.

Engineering college then allowed me to discipline myself and stop doing every thing from scratch one you have tried it once. This was reinforce by my first professional experiences.

Now, I reached at lot of domains in IT through all my learning phases and professional experiences and I can describe myself as a Backend developper (people building the behind of the scene to ensure an application works correctly). I love devops and artificial intelligence, and I am following and learning a lot of influencer and researching in those subject.

Hope it was nice to read, and Happy New Year 🙂

en_US