- Legacy Code Never Goes Away
- Glue Logic: A Sticky Business
- Is Python a Scripting Language or a Full Development Language?
- C++ Design Issues
- Conclusion
- References
Glue Logic: A Sticky Business
In this context, glue logic is simply a piece of Python script that allows you to call your legacy C++ programs, with no need to change them. Suppose we have a bunch of such C++ programs that must be called from Python, with the major requirement that we cannot make any changes to the C++ code. In other words, C++ code exists and is in use by real users. We can call it—but not change it!
With this requirement in mind, let's look at an example of the glue logic approach.
Calling C++ Programs from Python
Let's say we have a really simple C++ program (called CPlusPlus0xProject) that we want to call from Python. Listing 1 illustrates an excerpt from the C++ program.
Listing 1A simple C++ program.
int main() { cout << endl << "Now calling doSomeMemoryWork()" << endl; doSomeMemoryWork(); cout << "Now calling getPersonDetails()" << endl; getPersonDetails(); return 0; }
How do we run this C++ program from Python? This goal is achieved with the Python script in Listing 2.
Listing 2Python invocation of a C++ program.
import os, errno import subprocess as sp def invokeProgram(): try: print('Just before Python program invocation') p = sp.Popen(['/home/stephen/CPlusPlus0xProject'], stdout = sp.PIPE) result = p.communicate()[0] print('CPlusPlus0xProject invoked' + result + '\n') except OSError as e: print('Exception handler error occurred: ' + str(e.errno) + '\n') if __name__ == '__main__': invokeProgram()
In Listing 2, our simple C++ program is invoked from Python by using the subprocess module. The script imports a few standard modules, defines a function, and then has a main section. The C++ program can be anything you like; Listing 2 is essentially the same as running the C++ program directly from the console.
Listing 3 shows the combined Python and C++ program output.
Listing 3The Python and C++ program output.
Just before Python program invocation CPlusPlus0xProject invoked Now calling doSomeMemoryWork() Function name: doSomeMemoryWork() Before memory assignment a = aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa b = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb c = cccccccccccccccccccccccccccccc After memory assignment a = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb b = bbbbbbbbbbbbbbbbbbbbbbbbbbbbbb c = cccccccccccccccccccccccccccccc Now calling getPersonDetails() Person just created is: John Doe Person name = John Doe Now inside the Person class destructor
Why go to the trouble of using Python like this? Isn't it just as easy to run the C++ program from the console?
Well, using Python like this gives you a great deal more power than is the case with the console. For one thing, you can take advantage of Python's exception-management facilities—this is the try-except block in Listing 2. If anything goes wrong inside the Python exception block, you'll see a message printed on the console. For example, let's change this line in Listing 2:
p = sp.Popen(['/home/stephen/CPlusPlus0xProject'], stdout = sp.PIPE)
to this:
p = sp.Popen(['./home/stephen/CPlusPlus0xProject'], stdout = sp.PIPE)
Running this erroneous Python code results in the following program output:
Just before Python program invocation Exception handler error occurred: 2
Notice the exception that has been caught and reported. Now, you might be thinking, "This fellow is very pessimistic in outlook, worrying about exceptions from the word 'go.'" This is a good point, but exceptions are generally an unavoidable fact of life. Exception handling is perhaps not the most glamorous of areas to code, but working hard on your exception logic makes for a more solid end product. This in turn provides for an improved end-user experience.
Clearly, the code being executed in these examples is very simple. But as you scale up the size of both the Python code and the C++ programs, you'll begin to see the power of the glue logic approach. A large number of C++ programs can be invoked from a fairly simple Python script.
Now let's take a closer look at Python exceptions.
Python Exceptions
Python has a powerful exception-management facility and is substantially documented online. Listing 4 shows a typical exception example.
Listing 4Python I/O exception management.
try: fh = open('/home/stephen/myFile.txt', "w") fh.write("A test file.") except IOError as e: print('Exception handler error occurred: ' + str(e.errno) + '\n') else: print 'Successfully updated file.'
The script in Listing 4 opens a file in write mode and then attempts to write to the file. If no errors occur, the output should be that associated with the else clause:
Successfully updated file.
If an IOError exception occurs, the except clause is executed.
The Python exception code we've seen so far is very similar to the equivalent Java (or even C++) mechanism. The major merit of such exception handling is that errors can be handled close to where they occur. If the code in question can't handle the exception, at the very least it should document the exception in a logfile and then rethrow it. The latter scenario then gives higher-level code (that is, the calling code) a chance to handle the exception. Think of this as the rule:
Exceptions are inconvenient, but they should never be ignored or swallowed by code without a really good reason.
Given that Python has strong exception-support facilities, is it a full development language?