Learning PyQt

One of my recent undertakings has been, to extend my knowledge of Python, which I was previously only capable of writing procedural code for, to include, how to write Object-Oriented Python.

In the process, I began to think of what advantages I might now have, with that ability. And one answer which presented itself was of the form, ‘I already know enough about the Qt Library, to use it for some C++ programs. It has a Python binding referred to sometimes as PyQt. With the ability to write Object-Oriented Python, I should also gain the ability to write GUI applications in Python – eventually.’

The result of my recent exercise can be found at this URL:

https://dirkmittler.homeip.net/binaries/

The compressed files which contain my first project using PyQt are named ‘PyQt_Test_1_s.gz‘ and ‘PyQt_Test_1_s.zip‘. Either of those compressed archives need to be unzipped to a folder, in which there should be a total of 4 Python scripts. Python 3 would need to be run on the script named ‘AppStart.py‘.

I’m sorry to start so small.

Oh, yes… In order for these scripts to run, the reader’s Python installation would need to include PyQt5. Not all do.

Dirk

Why C++ compilers use name-mangling.

A concept which exists in C++ is, that the application programmer can simply define more than one function, which will seem to have the same names in his or her source code, but which will differ, either just because they have different parameter-types, or, because they are member functions of a class, i.e., ‘Methods’ of that class. This can be done again, for each declared class. In the first case, it’s a common technique called ‘function overloading’. And, if the methods of a derived class replace those of a base-class, then it’s called ‘function overriding‘.

What people might forget when programming with object-oriented semantics is, that all the function definitions still result in subroutines when compiled, which in turn reside in address-ranges of RAM, dedicated for various types of code, either in ‘the code segment of a process’, or in ‘the addresses which shared libraries will be loaded to’. This differs from the actual member variables of each class-object, also known as its properties, as well as for entries that the object might have, for virtual methods. Those will reside in ‘the data-segment of the process’, if the object was allocated with ‘new’. Each method would be incapable of performing its task if, in addition to the declared parameters, it did not receive an invisible parameter, that will be its ‘this’ pointer, which will allow it to access the properties of one object. And such a hidden ‘this’ pointer is also needed by any constructors.

Alternatively, properties of an object can reside on the stack, and therefore, in ‘the stack segment of the process’, if they were just declared to exist as local variables of a function-call. And, if an array of objects was declared, let’s say mistakenly, and not, of pointers to those objects, then each entry in the array will, again, need to have a size determined at compile-time, for which reason such objects will not be polymorphic. I.e., in these two cases, any ‘virtuality’ of the functions is discarded, and only the declared class of the object will be considered, for resolving function-calls. Such an object ends up ‘statically bound’, in an environment which really supports ‘dynamically bound’ method-invocation.

First of all, when programming in C, it is not allowed to overload functions by the same name like that. According to C, a function by one name can only be defined once, as receiving the types in one parameter-list. And the only real exception to this is in the existence of ‘variadic functions,’ which are beyond the scope of this one posting. (:1)

Further, C++ functions that have the same name, are not (typically) an example of variadic functions.

This limitation ‘makes sense’, because the compiler of either language still needs to generate one subroutine, which is the machine-language version of what the function in the source-code defined. It will have a fixed expectation, of what parameter list it was fed, even in the case of ‘variadic functions’. I think that what happens with variadic functions is, that the machine-language code will search its parameter list on the stack, for whatever it finds, at run-time. They tend to be declared with an ellipsis, in other words with ‘…’, for the additional parameters, after the entries for any fixed parameters.

So, the way in which C++ resolves this problem is, that it “mangles” the names of the functions in the source code, deterministically, but, with a system that takes into account, which parameter types they receive, and which class they may belong to, if any. The following is an example of C++ source code that demonstrates this. I have created 3 versions of the function ‘MyFunc()’, each of which only has as defined behaviour, to return the exact data which they received as input. Obviously, this would be useless in a real program.

But what I did next was to compile this code into a shared library, and then to use the (Linux) utility ‘nm’, to list the symbols which ended up being defined in the shared library…

Source Code:

 

/*  Sample_Source.cpp
 * 
 * This snippet is designed to illustrate a capability which C++ has,
 * but which requires name-mangling...
 * 
 */

#include <cmath>
#include <complex>

 /*  If this were a regular C program, then we'd include...
  *
#include <math.h>
#include <complex.h>
  *
  */

using std::complex;

typedef complex<double> CC;

class HasMethods {
public:
	HasMethods() { }
	~HasMethods() { }
	
	CC MyFunc(CC input);
};

//  According to the given headers, there are at least 3 functions
// that I could define below. First, two free functions, aka
// global functions...

double MyFunc(double input) {
	return input;
}

CC MyFunc(CC input) {
	return input;
}

//  Next, the member function of HasMethods can be defined, aka
// the supposed main 'Method' of a HasMethods object...

CC HasMethods::MyFunc(CC input) {
	return input;
}

 

(Updated 4/12/2021, 21h30… )

Continue reading Why C++ compilers use name-mangling.