Monday, November 22, 2004

Design by contract for Python

Plosch, R., Ch Doppler Laboratory of Software Engineering, Johannes Kepler University of Linz

Software Engineering Conference, 1997. Asia Pacific ... and International Computer Science Conference 1997. APSEC '97 and ICSC '97. Proceedings, Vol., Iss., 2-5 Dec 1997, Pages:213-219

Building an Object-Oriented software class library in a customizable format is one of the main tasks in understanding the OO-Software of a particular application. This is called Design by Contract (DBC). Many of these features are present in static typing languages like Java, C++, Eiffel, etc. But these languages realize DBC only in development phase of the Software development life cycle. To carry out DBC even in analysis and design one has to have a dynamic typed interpreted language such as Python and this paper deals with how to introduce DBC in Python.

The main goal of DBC is to introduce some sort of invariants at different levels of the Object-Oriented Constructs. These levels are the:

(i)      Class level invariants

(ii)    Methods invariants

(iii)    Loop invariants and

(iv)   Check instructions

Lets look what are these invariants and how they provide customization and better understanding of software.

Invariants are set of “preconditions” and “post conditions” that has to assert during the execution of the software. For Example:

put (v: T) is -- add item v to queue

require

not full

do

ensure

...

count = old count +I;

(old empty) implies (item() = v)

not empty

item((last - 1 + capacity) \\capacity) = v

end -- put

Here put (v, T) is to put element “v” in queue “T”. So the precondition is defined by require statement “not full” that means the queue should not be filled and the post condition is given by ensure statement saying the capacity of queue is greater by one and the last element is “v”. Any implementation (overridden) which does not adhere to it will fail. Similarly one can introduce invariants at class level as you can see below:

deferred class Person feature

invariant

...

age >= 0;

age < 100;

len(name) 0;

socialSecurityNumber > 1000;

end

Here age of the person should be between 0 and 100 and SSN should be above 1000. Class invariants are checked during the instantiation of the Object. Now all the overriding classes also inherit its pre and post conditions. Similarly it is applicable to overridden methods also.

Check instructions are satisfied at the point of definition. And loop invariants are check on loop variables.

To achieve this in dynamic typed interpreted language, the pre and post conditions are checked at the runtime. Because of its dynamic typing nature all the parameters has to type checked during the runtime. So how do you incorporate pre-post conditions (DBC) in Python with out changing the language itself because changing the language involves lot of overhead and moreover the developers has to learn these new concepts. To do this the author has introduced meta-programming approach which is interpreted by the Python interpreter.

Multiprogramming approach is achieved by introducing a wrapper class for all the classes which uses DBC. This is done in the __init__() a constructor of a class. The wrapper object is initialized and the actual object is set on it. So every method call which has invariants calls the wrapper object by wrapper.checkBefore() which is precondition check at the beginning of the method and wrapper.checkAfter() which is a post condition check at the end of the method.

So how can one introduce these checks? This is done by the parser during the generation of the intermediate code. And the logical statements (invariants) are provided in the form of configuration files to the parser while generating the code. This shows the simplicity of the design with out changing the language at all. So by this mechanism of meta-programming it is easily to incorporate Design By Contract in dynamic typing language like Python.

Python - a glue to programming languages

ABSTRACT
The paper covers the history of python how it evolved to its current state. It describes the main design goals which made the authors develop such a language. Then the paper goes in detail about the language features and what it offers to the programmers. It also enumerates some of the disadvantages of the language.

1. INTRODUCTION
Python was created in the early 1990s by Guido van Rossum at Stichting Mathematisch Centrum (CWI) in the Netherlands as a successor of a language called ABC. He decided to create a language that was generally extensible so Guido and his Python core development team moved to BeOpen.com to form the BeOpen PythonLabs team and later in 2001, the Python Software Foundation (PSF) was formed, a non-profit organization created specifically to own Python-related Intellectual Property.
Python design objective was to keep the syntax simple also enable it to be used as a scripting language. The language has grown immensely since its introduction. It was incorporated into JPython (a python version for Java), CPython (for C), for C#, and includes all powerful features of Perl, Tcl/Tk, Network programming, etc and is still growing.

2. MAIN DESIGN GOALS
1.      A language that uses an elegant syntax for better readability
2.      Provides a multi-paradigm programming language. This means it should permit Object Oriented approach like C++ and java, functional programming features for to perform mathematical functions like LISP and Scheme, scripting language like JavaScript, pattern and text manipulation like Perl, and aspect-oriented approach
3.      The language that is portable and works on different operating systems. This made python an interpretive language
4.      Provides a glue between modules developed in several languages. This goal makes integrating modules from different languages easier
5.      Provide dynamic-typing and implicit garbage collection for memory management
6.      Provide dynamic name resolution, that means allowing method and variable names to be bound during program execution

3. FEATURES
Python is ideally suited for rapid prototyping of complex applications. Its various features from the different programming paradigms are now discussed.

3.1 Features of Object Oriented Programming
Python includes most of the features of the current OOP languages. It provides multiple-inheritance as in C++, user defined Abstract Data Types, Encapsulation and in Python “packages” are the way of structuring module’s namespace by using “dotted module names.”
Each package is stored a folder and the folder contains “__init__.py” to tell you that it is right package instead of some unknown folder in the path. The modules are like classes and each are accessed by “.” operator to qualify a module as in Java.
In Python every variable is an object unlike Java or C# where primitive types are allowed. For example:
A = 10
B = A
B = 5

In the above case both A and B points to the same object in the memory so any change in one value will change in the value of other. Methods are also objects in Python that means that one can pass methods as objects to some other methods and call them at later point in time. The following is an example of how a class is defined in Python:
class Bag:
    def __init__(self): “”” constructor
        self.data = []
    def add(self, x):
        self.data.append(x)
    def addtwice(self, x):
        self.add(x)
        self.add(x)

Python also provides exception handling and memory management similar to Java and C# thus the developer can create exceptions of their own kind or type. The construct looks like:
try:
     <st1>
     <st2>
except  (<exceptionType1>, <exceptionType1>,..):
     <st3>

Multiple exceptions can thus be handled at the same level unlike Java. It also supports a single except clause without specifying the type and it also supports “finally” clause like that of Java.

3.2 Features of a Scripting Language
Python is an interpreted language and provides all facilities as that of a scripting language. It also has features similar to Perl and shell scripts making it possible to run programs written in scripts as a batch files.

3.3 Features of Functional Languages
Functional language support is provided by the python though not as completely like LISP or Scheme. Its way of defining a function is similar to these languages. In Python language expressions return “anonymous” functions as results. This is needed wherever you cannot define a function and avoids lot of function declarations.
Examples:
1) increment = lambda x: x + 1
2) lmap = ( lambda f, lst:
    if lst == []:
        return []
    else:
        return [ f( lst[0] ) ] + lmap( f lst[1:] ) )

3.4 Other Features
Dynamic Typing
Python supports dynamic typing. This means there is no need for the variable to be declared in python. Wherever it is occurs for the first time the variable is declared at that point. The type is therefore defined at run time that means the type is defined based on the value it takes and can change over the period of execution.

Readability
Another important feature of the language is its readability. Python does not have any block structures. In-fact a block is determined by the indentation of the statement, so all statements which are part of the same block must be indented equally:
def f(a, b):     a = b       print a;   Argument Passing Argument passing in Python is pass-by-value. But the value is the reference value not the copy of the object as in Java. This is obvious since there are no primitive types for the actual value to be passed. Also like C++ the functions in Python can be declared to take default arguments:  
def ask_ok(prompt, retries=4, complaint='Yes or no, please!')
where formal parameters “retries” and “complaint” can take default values when one calls if no parameters are called onask_ok();Also the values are evaluated at the point of function definition in the defining scope and are evaluated only once. For example:
i = 5
def f(arg=i):
    print arg
i = 6
f()
 
After the last statement it prints 5 rather than 6.
 
Python also supports both positional arguments and named arguments. For positional arguments the parameters should appear according to the position and for achieving the named parameter, Python uses something called “Keyword-Argument.”
 
def parrot(voltage, state='a stiff', action='voom')
parrot(1000) // positional parameter
parrot(action = 'VOOOOOM', voltage = 1000000) // named arguments
parrot('a thousand', state = 'pushing up the daisies') // positional and named argument where voltage= ‘a thousand’, state = 'pushing up the daisies' and action takes the default value
parrot('a million', 'bereft of life', 'jump') // here every parameter is a positional parameter.

Another feature is to specify a function that can be called with an arbitrary number of arguments. These arguments are wrapped up in a tuple. Before the variable number of arguments, zero or more normal arguments may occur.
def fprintf(file, format, *args):
    file.write(format % args)

Conditional statements and Loops
Python both supports “if-else” and “if-elseif-else”, “for” loop and “while” loop constructs. Multiple selection can be achieved by if constructs.
if x < 0:
     <st1>    
elif x == 0:
     <st2>
else:
     <st3>

Python does not have “switch-case” construct as a separate multiple selection process. Also conditions can contain any operations not just comparisons. All comparison operators have the same precedence that is lower than that of all numerical operators. For example, a < b == c tests whether "a" is less than "b" and moreover "b" equals "c". Unlike C variant where it tests like (a < b) == c.

Debugging
Python also provides facilities for introspection, so that a debugger or profiler (or other development tools) for Python programs can be written in Python itself. There is also a generic way to convert an object into a stream of bytes and back, which can be used to implement object persistency as well as various distributed object models.

4. CONCLUSION
Thus we see Python provides a variety of features. Some drawbacks of Python are due to its dynamic typing (reducing reliability), argument passing (like positional and name passing creates conflicts), interpreter based language (lower execution efficiency), and the negative aspects of multiple-inheritance. Also since Python program has to be properly indented, writability is compromised.
In conclusion Python attempts to glue many contemporary languages and serves as a good testing tool, rapid prototype development tool and a batch/scripting tool.