Sunday, February 2, 2025

History and Development of Programming


In the beginning of the Information Age, computers were programmed by wiring instructions into the circuitry. One of various calculations was selected using switches or making connections to different logical units by wires.

The wiring of the switch boards became a thing of the past with the invention of vacuum tubes, and then the transistors.

Claude Shannon demonstrated the application of binary logic in computing to complete the software concept of modern computing.

Meanwhile, John Von Neumann’s concepts of shared-program technique and conditional control transfer, decoupled machine (hardware) from their execution (software), re-locatable code, and later subroutines and flow control.

Jaquard (1804, France) designed a loom that performed predefined tasks through feeding punched cards into a reading contraption
At first, programming was done by typing in 1's or 0's that were stored on different information carriers, like paper tapes, punched hole cards, later magnetic drums, and much later magnetic and optical discs.

The next development was to combine groups of instruction into so called words, and written in shorthand as opcodes (Hopper 1948). The opcode was translated by another program into zeroes and ones, which formed machine instructions. These formed the modern day machine languages.

Programming in initial crude languages generated a lot of what was called, "spaghetti code", which still exists today, but only in much larger projects. Subroutines were developed to avoid this pitfall by climbing up the abstraction level.

Then IBM created FORmula TRANslator (1952), which was much more intuitive for computation. Fortran programs were then translated to machine readable format. It was the first major programming language as we know today.

In the meantime hardware developments made live for programmers a lot easier. But programs still had to be rewritten for each type of processor.

All machine specific tasks were delegated to a common module called Operating System (OS). The first fully portable language, C, was developed. Now, programs could be written independent of the underlying hardware, using libraries to perform all machine specific instructions. SourceCode could be reused, only to be recompiled when it had to run on other machines.

After Portability, came the problem of Reusability, and Object Oriented Programming was introduced with the development of Smalltalk. GUI’s were created to expedite the creation of software.

References:
1. Introduction to Software History – http://www.thocp.net/software/software_reference/introduction

Communism vs Free Markets vs Capitalism



Economists sold us "Free Markets" over "Communism", 
but all we got was "Capitalism"! 




Programming at a More Abstract Level: A case for C++ in embedded systems

Programming at a More Abstract Level: A case for C++ in embedded systems

Programming at a More Abstract Level: A case for C++ in embedded systems

Most critics try to give the justification that when performance is at the premium, you must go down the level of abstraction. But rarely do they try to figure out, how much advantage is actually achieved by doing so.

A typical graph of optimization vs. effort would look like this –

Optimizations mostly happen at the algorithm level, no amount of machine code writing can account for such huge differences in performance. More often than not, stooping to lower levels of abstraction, only adds to the baggage to be carried through the rest of the product life cycle, and hinders important optimizations. It is only at the fag end of the optimization cycle, that removing abstraction is not offset by its negatives. Hence, it should be performed only when the whole software product is completed, decisions taken, and it’s fully ready for mass production – commercialization. They don’t start painting the car while the fittings and hammerings not yet done. The irony is that we start designing the color of the car when we don’t yet know what the car is going to be like; we start writing C & assembly code when the product’s not yet ready.

------------------------------------------------------------------------------------------------------------

"Abstraction is a process whereby we identify the important aspects of a phenomenon and ignore its details." -- [Ghezzi et al, 1991]

This is a review of only the performance impact of choosing C vs C++ language. Provided below is an analysis of the C++ code and its C translation –

(Thought the tone is pre-judgmental, the first 4 reason why C can be slightly faster, and methods for avoiding it, and the last 2 show why C++ can be faster)







C++ Method Invocation All C++ methods when translated to C end up with an additional parameter. This might appear to be a big performance overhead. In reality however, the code in C will also have to access the common data structure via an array index or some other mechanism.
Object Construction Whenever an object is constructed, C++ will invoke the constructor. Sometimes this might be an addition overhead. This overhead can be reduced by defining the constructor inline. In most cases however, the constructor is actually replacing a routine that would have been used to initialize the data structures in a conventional C program.
If a program declares a lot of global objects, object construction can be a big overhead at program startup. C++ invokes constructors for all global objects before main() is called.
Object Destruction As you can see from the C code, whenever an object goes out of scope or is explicitly deleted, C++ invokes the destructor for the object. This overhead can be reduced by only defining destructors when they are really needed (i.e. some action is required when object is deleted). Inline destructors can also be used to reduce the overhead.
Static Access The C code above shows that static member functions and variables do not correspond to an instance of the object. Thus they are accessed without indirection of the object. This can be useful in defining methods which need C level function call conventions. One good use for static member functions is to implement interrupt service routines (ISRs). ISRs handlers typically need to be C type functions. In most implementations, C++ static functions can be directly used as ISR handlers.
Quicker Optimization The higher level of abstraction and modularity in C++, topped with the available of better standard libraries, speeds up the optimization phase, enabling more conceptual and algorithmic optimizations. For example, stl vector containers built from arrays will be regularly used for variable sized data in C++, as against linked lists in C.
Generic Programming Compile time Generic Programming provided by C++ avoids C function call overheads, created as a result of modularizing. (Note: Modularizing is essential, as you don’t want a single bulky function). Below is a typical example using C++ sort lib. vs C qsort lib., but all computational libraries fall under this.

Running Times





Data Type C (library) C (hand-coded) Numerical Recipes Ratio 1 C++ (C array) C++ (vector class) Ratio 2
int 5.90-5.92 1.54-1.65 1.46-1.50 3.7 1.12-1.16 1.11-1.14 5.3
short 9.03-9.03 1.73-1.80 1.58-1.59* 5.1 1.17-1.20 1.17-1.19 7.7
byte 7.87-7.89 0.98-1.02 0.98-1.00 7.9 0.70-0.73 0.70-0.73 11.0
float 7.08-7.10 2.38-2.50 2.48-2.55 2.9 1.96-2.02 1.97-2.02 3.6
double 16.42-16.45 2.70-2.93 2.72-2.83 5.8 2.28-2.35 2.28-2.37 7.1

• Numerical Recipes is the code from Numerical Recipes, a combination of multiple algorithms, aborting quick sort on data set less than 7, and performing linear sort.
• Ratio 1 is hand coded divided by the library routine
• Ratio 2 is C++ sort divided by C qsort

------------------------------------------------------------------------------------------------------------
If i were to say, i was satisfied at the level of interest shown by us, incl. me, to get an approval for a change in the language of implementation of our future projects, i would be definitely lying.
Not only does C++ score completely over C in terms of code size, effort spent, etc, it indirectly has advantages in performance.

Here are 2 samples of real life potential opportunities for optimization in our own OpenGL-ES project, using C++'s Generic Programming and STL tools.
1. In tests using textured objects, about 40% of the time is spent in a single module, which involves running a few reasonably coupled routines, each of which can be performed in a number of ways by the user. We are currently forced to write them independently, instead of compiler optimizable combinations, to avoid bloating the code. The solution was trivial using templates.
2. On an average about 5% of application time is spent on one of the standard data structure maintenance. We are forced to forfeit the use of highly optimized, industry-standard libs.
[Note: though not everybody in the team may know all of the language features, it permits use of special features in specific cases, with the bulk of the project being C programming.]