# Comparison of high-level computer programming languages

anorlunda
Mentor
One thing I think is undeniably true, is that programming languages are the most fun of all topics among programmers.

I'm reminded of when the Ada language was first introduced. They published a document called the rationale, explaining why they wanted this new language. The rationale (to the best of my memory) said that in the history of DOD software projects, that every single project created it's own language. The exception was Jovial which had been used in 2 projects. Ada was intended to be the one and only language for all future projects.

So, did Ada become the language to end all languages? Heck no.

I'm confident that as long as humans write software, they will continue creating new programming languages, and there will be a credible rationale for each and every one of them.

bhobba, Klystron and FactChecker
FactChecker
Gold Member
So the real question to ask, is what is more important to you: getting the results tomorrow by writing low level code for a day, that displays the results near instantly, or to write code that takes a few minutes, but that you could jot down in an hour. If it's the results you want, then obviously use the high-level stuff. If you want to re-use your code as a library, then use the former.
Good advice, but I think that you are being very conservative in your estimates. Using a low-level language to mimic what one can get in one hour of MATLAB programming could easily take weeks of programming.

Alex Petrosyan and jedishrfu
Good advice, but I think that you are being very conservative in your estimates. Using a low-level language to mimic what one can get in one hour of MATLAB programming could easily take weeks of programming.
That’s assuming you could get equivalent behaviour. Most Matlab functions are exceptionally smart and catch things like poor conditioning early. Besides, when was the last time Python segfaulted because you used a negative array index?

FactChecker
cronxeh
Gold Member
I think for general benchmarks (i.e Python vs Java) there are already good ball-park figures out there (i.e https://benchmarksgame-team.pages.debian.net/benchmarksgame/faster/python.html and https://www.techempower.com/benchmarks ) but for real-world application its not really worth talking about a single core execution or even single machine execution.

So really it comes down to speed of iteration, concurrency, parallelism, and community. I personally would not reach for C/C++ as it does not pass 'speed of iteration' mustard test, or community for that matter. So in my humble opinion:

For small-scale application, data science, and proof of concept work - Python3 is lingua franca.

For really-really large-scale applications with multiple distributed teams working together, deployed across 10K+ servers, there are really only 2 choices - Java, and if you like to skate uphill and write most of your own libraries for everything, Golang. There is also Scala as a contender, but it has its own issues (as in: all software problems are people problems, and with Scala you'll get "implicit hell").

Svein
Python, Java, Julia, whatever: You are all assuming that there exists a software "machine" that handles all the difficult parts for you. Some of us do not have that luxury - writing device drivers, interrupt handlers, process schedulers and so on. In that case your environment and requirements are radically different:
• You are writing on "bare metal". No libraries are available to help with the difficult parts.
• Usually your routines have to be short, fast and error-free. An Ethernet hardware driver is called millions of times each day - bugs are not tolerated
• Debugging the routines calls for very special equipment (you can not insert debugging printouts, since the high-level printing routines are not available)
Here is an example of a small part of an interrupt driver for an Ethernet hardware chip:
Code:
/*m************************************************************************
***  FUNCTION: _ecInitInter
***************************************************************************
***  PURPOSE:  Sets up the interrupt structure for EC
***************************************************************************
***
***  WRITTEN BY     : Svein Johannessen 890711
***  LAST CHANGED BY: Svein Johannessen 900216
**************************************************************************/

#include "ec.h"
#include "sys/types.h"
#include "sys/mbuf.h"
#include "ecdldef.h"
#include "ecextrn.h"
#include "net/eh.h"

void (* _ecRx)() = NULL;
void (* _ecTx)() = NULL;
void (* _ecFatal)() = NULL;

short _ecRxRdy();
short _ecTxRdy();

void interrupt EC_INT();

u_char int_babl;                    /* babble */
u_char int_miss;                    /* missed packet */
u_char int_merr;                    /* memory error */
u_char int_rint;                    /* rx packet */
u_char int_tint;                    /* tx packet */
u_char int_idon;                    /* init done */

u_short _ecMERR;
u_short _ecLastCSR0;

EXPORT short _ecInitInter(eh_idone,eh_odone)
void (* eh_idone)();
void (* eh_odone)();
{

_ecRx = eh_idone;
_ecTx = eh_odone;
_ecFatal= NULL;
_ecMERR = 0;
_ecLastCSR0 = 0;

/* Here someone must set up the PC interrupt vector ... */
if ( ( _ecRx == NULL ) || ( _ecTx == NULL ) )
return ERROR;
return NOERROR;
}

/*f************************************************************************
**  FUNCTION: _ecRxInt
***************************************************************************
***  PURPOSE:  Handles a receive interrupt
***************************************************************************
***
***  WRITTEN BY     : Svein Johannessen 890711
***  LAST CHANGED BY: Svein Johannessen 900216
**************************************************************************/

static void _ecRxInt()
{
struct  mbuf *cur_buff;
register short rxerr, good;

/* see if the LANCE has received a packet  */
rxerr = _ecRecPacket(&cur_buff);        /* get address of data buffer */

if ( cur_buff != NULL ) {
good = (rxerr==NOERROR) && !(int_miss || int_merr);
(*_ecRx)(cur_buff,good);
}
else
int_rint = 0;
(void)_ecAllocBufs();         /* Allocate more buffers */
}
/*f************************************************************************
***  FUNCTION: _ecTxInt
***************************************************************************
***  PURPOSE:  Handles a transmit interrupt
***************************************************************************
***
***  WRITTEN BY     : Svein Johannessen 890712
***  LAST CHANGED BY: Svein Johannessen 900418
**************************************************************************/

void _ecTxInt()
{
struct  mbuf *cur_buff;
short good, Coll;

good = !(int_babl || int_merr || TxBad);
if (cur_buff!=NULL)
(*_ecTx)(cur_buff,good,Coll);
}

/*f************************************************************************
***  FUNCTION: _ecIntHandler
***************************************************************************
***  PURPOSE:  Handles an interrupt
***************************************************************************
***
***  WRITTEN BY     : Svein Johannessen 890712
***  LAST CHANGED BY: Svein Johannessen 900418
**************************************************************************/
/**
***  OTHER RELEVANT  :
***  INFORMATION     :
***
**************************************************************************/

extern short num_rx_buf;             /* wanted number of rx msg desc */
extern short cnt_rx_buf;             /* actual number of rx msg desc */

void _ecIntHandler()
{
register u_short IntStat;
register u_short ErrStat;

IntStat = RD_CSR0;

while (IntStat & INTF) {
_ecLastCSR0 = IntStat;
int_babl = ((IntStat & BABL)!=0);
if ( int_babl )
WR_CSR0( BABL);
int_miss = ((IntStat & MISS)!=0);
if ( int_miss )
WR_CSR0( MISS);
int_merr = ((IntStat & MERR)!=0);
if ( int_merr )
{
_ecMERR++;
WR_CSR0( MERR);
}
int_rint = ((IntStat & RINT)!=0);
if ( int_rint )
WR_CSR0( RINT);
while ( int_rint ) {
_ecRxInt();
int_rint = _ecRxRdy();
}
int_tint = ((IntStat & TINT)!=0);
if ( int_tint ) {
WR_CSR0( TINT);
_ecTxInt();
}
int_idon = ((IntStat & IDON)!=0);
if ( int_idon )
WR_CSR0( IDON);
if ( int_miss && (cnt_rx_buf==0)) {
_ecDoStatistic(FALSE,FALSE,int_miss,FALSE);
(void)_ecAllocBufs();         /* Allocate more buffers */
}
if (_ecFatal!=NULL) {
ErrStat = 0;
if ((IntStat & TXON)==0)
ErrStat |= EC_TXSTOPPED;
if ((IntStat & RXON)==0)
ErrStat |= EC_RXSTOPPED;
if ( int_miss && (cnt_rx_buf!=0))
ErrStat |= EC_SYNCERROR;
if (ErrStat!=0)
(*_ecFatal)(ErrStat);
}
IntStat = RD_CSR0;
}
WR_CSR0( (INEA | CERR));
}

/*f************************************************************************
***  FUNCTION: _ecInterrupt
***************************************************************************
***************************************************************************
***
***  WRITTEN BY     : Svein Johannessen 890830
***  LAST CHANGED BY: Svein Johannessen 890830
**************************************************************************/

void interrupt _ecInterrupt()
{
_ecIntHandler();
}

/* End Of File */

Staff Emeritus
2019 Award
Python, Java, Julia, whatever: You are all assuming that there exists a software "machine" that handles all the difficult parts for you.
Well, the thread title is "Comparison of high-level computer programming languages" (emphasis mine).

FactChecker
Gold Member
but for real-world application its not really worth talking about a single core execution or even single machine execution.
Your "real-world" is far different from my "real-world".

cronxeh
Gold Member
Your "real-world" is far different from my "real-world".
yes, but are they both equally imaginary?

Svein
Well, the thread title is "Comparison of high-level computer programming languages" (emphasis mine).
Yes, but what exactly does it mean?
• High-level as in "more abstract than assembly language"?
• High-level as in "will only run on a high-level computer (containing a mass storage device and a sophisticated operating system)"?

Normally I'd say the first one, but the OP seems to want to compare efficiency of 3.5-4GL math suites, presumably ignoring 3GL offerings, or 2GL possibilities.

FactChecker
Gold Member
I think there is a generational divide. I have always considered C/C++ to be "higher level", but that seems very out of date now. People can produce programs using MATLAB/Simulink or MatrixX/SystemBuild that would have been inconceivable long ago. And I am sure that others have similar experience with other 4th generation languages.

PS. I will never forget my reaction when MathCad gave us a language that automatically converted units and helped in dimensional analysis but the aerospace industry turned to Ada, which enforced everything but helped in nothing. IMHO, that was a HUGE step backward from 4'th generation languages.

PPS. I would still consider C/C++ to be an essential language for any professional programmer.

Klystron and S.G. Janssens
S.G. Janssens
I think there is a generational divide. I have always considered C/C++ to be "higher level", but that seems very out of date now.
I don't think it's out of date - at least not for modern C++ - but perhaps that just means that I am myself out of date.

I'm rather more "out of date" than probably anybody else, but my (pro) experience is in CoBOL (which really does deserve the levied humour, but also really does run rings around anything else in its domain). I tend to use 4GL's as analysis tools to get a grip on the problem, rather than production languages.

On the other hand I worked with a rather more experienced (ie: older, with a previous generation methodology under his belt) programmer who could work wonders with a 4GL in a production environment... granted, by basically ignoring all the "fancy" stuff and concentrating on its capabilities closest to the metal.

Just wondering why I haven't seen any references to ForTran or Algol in the last four pages. Surely they both have OO, advanced libraries and decent graphics capabilities by now ?

Last edited:
FactChecker
FactChecker
Gold Member
I think that a targeted language like COBOL has great advantages over general purpose languages. I have some experience with several simulation languages for discrete event, continuous, and mixed models, statistical languages like R and SAS, scripting languages, etc. They are all better in their domain than general purpose languages.
FORTRAN has advantages for engineering analysis that I have never seen matched. I especially like the namelist capability for easily printing and reading large amounts of data in a readable format. Many programmers think that they can duplicate that capability in C or C++, but they never succeed.

Klystron
AHAH. you cannot compare code with other if it is not optimized.
Try ATLAS (Autotuned Lapack) lib on linux, hard to use but so fast ! People optimize it to death since 30 years.

"The C++ code used simple Gauss-Jordan elimination taken from the book "Numerical Recipes in C" :
I think you can gain a 10 factor with ATLAS. maybe other language like Julia or R use different algorithm like : preconjugated gradient (ultra ultra fast for sparse matrix), decomposition method, etc....

For a easy use, Eigen 2 is the best in C++

Klystron
Gold Member
From experience on FORTRAN, C/C++, Pascal, Common-Lisp, smalltalk; within object oriented programming.

[post edited for brevity.]
FORTRAN has advantages for engineering analysis that I have never seen matched. I especially like the namelist capability for easily printing and reading large amounts of data in a readable format. Many programmers think that they can duplicate that capability in C or C++, but they never succeed.
FORTRAN proved an excellent language for real-time data collection, filtering, and storage; CFD and similar computational models. Good performance and internal operations. Largely intuitive flow control. Impressive ability to optimize interrupts and distribute processes. Mature compiler. Little or no language derived internal data loss or corruption that I know.

C/C++ runs like a different animal. When programming master control code where human lives are at risk; e.g., in a full-motion simulator; when high-level iterative code requires direct access to low-level synchronization pulses; when sys-level code needs to flip bits and read/write registers; choose C++.

C++ operated well driving human factor repetition rates around 30 frames/sec. With persistence of vision ~7 frames, a 30hz frame rate provides over 4x margin for visual and audio displays. Conditional operator ( example "if" statements) rates actually assist performance with I/O functions during frames. C++ easily controls other electronic devices.

smalltalk, Common Lisp honorable mention. Simplify language into two objects: variables and functions. Although I rarely used these languages professionally, they taught me much about functions, manipulating objects and led to ideas for adaptive structures such as sparse matrices, data driven adaptations, and error correcting code.

Last edited:
AHAH. you cannot compare code with other if it is not optimized.
Try ATLAS (Autotuned Lapack) lib on linux, hard to use but so fast ! People optimize it to death since 30 years.
Using ATLAS is well worth the effort today if you do a lot of linear algebra. (Matrix multiplication, matrix inversion, eigenvalues, etc.) ATLAS generates a BLAS (basic linear algebra subroutines) that is tuned for the exact machine you ran it on. ISA, cache sizes, cpu speed, memory speed, etc. are all taken into account. Then you can use BLAS directly, or use LAPACK or LINPACK which use the BLAS routines with higher-level interfaces.

Back to another topic, if you are writing a program that you will run once, or a few times, high levels of optimization are a waste of time, even if a compiler is doing it for you. If you are writing code that will be run millions of times, or code that needs to meet real-time execution constraints, the more the compiler can do for you, the better. In particular, the SPARK compiler (different from Apache SPARK which is a web application framework) makes writing real-time code much easier. (Easier than other hard real-time tools anyway.)

What makes hard real-time hard? The difference between your first-cut prototype and the requirements. Have I seen cases where that required a million times speed-up? Yep, and made it too. Some of that speedup came from better algorithms and better optimization, but most of it was taking the best algorithm and coding it to work with very sparse matrices.

Klystron
Out of personal experience, choosing the right language can have up to several percent speedup, if the language has a decent compiler and you know how to turn on all of its optimisations. Hell even Java which should run infinitely slower runs within 5% of some of the C++ that I've written. If you want to optimise - do so for readability in your programming style/paradigm. Even though C++ has the crown for the highest performance code, it can be outperformed by rust, go and Ocaml, not because the languages are better, but because the paradigm that they enforce requires you to write easily optimiseable code, that you can also more easily understand.

Klystron
Klystron
Gold Member
Out of personal experience, choosing the right language can have up to several percent speedup, if the language has a decent compiler and you know how to turn on all of its optimisations. Hell even Java which should run infinitely slower runs within 5% of some of the C++ that I've written. If you want to optimise - do so for readability in your programming style/paradigm. Even though C++ has the crown for the highest performance code, it can be outperformed by rust, go and Ocaml, not because the languages are better, but because the paradigm that they enforce requires you to write easily optimiseable code, that you can also more easily understand.
Design remains critical not only to optimization but also to operation. Active C++ code runs robustly with attention to error conditions.

C languages produce terse code. Write voluminous comments. The interpreter filters out comments.

FactChecker
Gold Member
Even though C++ has the crown for the highest performance code, it can be outperformed by rust, go and Ocaml, not because the languages are better, but because the paradigm that they enforce requires you to write easily optimiseable code, that you can also more easily understand.
For numerical calculations (as in a lot of scientific/physics programs), FORTRAN is reputed to be the fastest. It is targeted at those types of programs and avoids tempting features that tend to slow calculations down. I have not personally done tests to confirm that reputation of FORTRAN, but I have seen a few.

Klystron
Gold Member
For numerical calculations (as in a lot of scientific/physics programs), FORTRAN is reputed to be the fastest. It is targeted at those types of programs and avoids tempting features that tend to slow calculations down. I have not personally done tests to confirm that reputation of FORTRAN, but I have seen a few.
I have seen and conducted tests of FORTRAN computation modules including tests while performing real-time I/O. I've seen C++ test results running Mandelbrot sets (functions) on networked SGI's, even Crays. Agree with FactChecker and Alex. The CFD system design comes first. Choose language modules in the system for optimum function performance.

Once removed from the front-end interface which may be reading instruments or inputting data, and the fast computation intensive modules, computer speed measured in operations/time (flops, etc.) may not provide the best metric. Near-time analysis of function reliability and spot-check data integrity provides an "outer, slower" command loop sensitive to error. This outer command structure should not need to run at speeds comparable to computation but at the optimum frame rate for system control.

The statement "C programs call FORTRAN functions" though lacking meaning on a distributed network, captures the essential truth that both languages provide optimizations depending on use.

Last edited:
FactChecker
FactChecker
Gold Member
The statement "C programs call FORTRAN functions" though lacking meaning on a distributed network, captures the essential truth that both languages provide optimizations depending on use.
My experience with interfacing C and FORTRAN (and Ada) in scientific applications is that the matrix index swapping between column-major and row-major was a real hassle. Also the different array starting index (0 versus 1) was a problem. Those differences made the interface difficult and error-prone.

Klystron
Gold Member
Yes, not only indices. Suppose you have several different platforms performing computations with different significant digits (so to speak). Researcher expects to retain data commensurate with sampling uncertainty and within function restrictions. The programmer offers least significant digits among multiple processors?

Let's consider recursive subroutines. Given the restrictions on recursive functions can the programmer ensure reliable results across the network [here I'm involving "hardware"; i.e., "stack" issues not directly related to language selection.] depending on the computation.

[Edit: Speaking of boundaries, I've exceeded the scope of this thread about language selection. Norm]

Last edited:
My experience with interfacing C and FORTRAN (and Ada) in scientific applications is that the matrix index swapping between column-major and row-major was a real hassle. Also the different array starting index (0 versus 1) was a problem. Those differences made the interface difficult and error-prone.
I'm a bit confused. I used Ada and needed an Ada library to interface with a BLAS written in Fortran. I declared several types with
pragma Convention (Fortran, T_...); the T to indicate Transposed. The parameters of the BLAS routines used these types, and I provided functions to convert from one to the other: function Transpose(Arr: in T_Complex_Array) return Complex_Array; and the reverse. (Fun detail, the bodies were identical--in source). Also there was a procedure version to avoid copying of arrays. My only problem was that I spent the entire project wondering off and on about how to write the transpose functions. They were only called by debugging and test code, so in that sense it was a non-issue. But..

For a large matrix, keeping both locations in L1 cache is a big win, although you expect the writes to overwrite the contents of the cache line, you want the the cache line resident so it doesn't get read for each write. So:

Code:
procedure Transpose(A: in Float_64_Matrix; T_B: out T_Float_64_Matrix) is
-- parameter checking and non multiple of eight handling omitted for clarity.
for K in 1..A'Length(2) loop
for I in 0..(A'Length/8) -1  loop
for J in 1,,8 loop
T_B(I*8+J;K) := A(I*8+J;K);
end loop;
end loop;
end loop;
end Transpose;
is much faster than the naive code--once arrays get large. Dividing the arrays into tiles that fit into 1/2 of L1D and transposing them should be a win, but I've never tried it.

Klystron
FactChecker