Flow Control


This section is not finished yet. Provides more examples and explanations.


Variables should contain values of at most one type at each control flow point. For example, this means that joining control paths using the same variable to contain both a string and a int must be avoided.

Let’s look at this example code.

def compiler_error(arg):
    v = 0              # v is an integer
    if arg:
        v = 1          # assign integer 1 to v
        v = ""         # assign string "" to v
    return v

def entry_point(argv): compiler_error(argv[1]); return 0
def target(*args): return entry_point

The control flow graph of the compiler_error function is shown in the following figure.


Merge point of a control flow with different types.

As you can see, at the merge point (highlighted in green), v2 can be either integer 1 or an empty string ''. this violate the RPython’s restriction.

It is allowed to mix None with many other types: wrapped objects, class instances, lists, dicts, strings, etc., but not with int, floats or tuples.

class Obj():

def flow_control_variables_unsupported(arg):
    int, floats or tuples cannot be mixed with None.
    i = None    # integer
    f = None    # float
    t = None    # tuple

    if arg:
        i = None
        f = None
        t = None
        i = 0
        f = 0.0
        t = (1, 2, 3)

    return i, f, t

def flow_control_variables(arg):
    It is allowed to mix None with many other types: wrapped objects, class
    instances, lists, dicts, strings, etc.
    o = None    # object instance
    l = None    # list
    d = None    # dict
    s = None    # string

    if arg:
        o = None
        l = None
        d = None
        s = None
        o = Obj()
        l = [1, 2, 3]
        d = {1: "123"}
        s = "hello"

    if o and l and d and s:
        print o, l, d[1], s

    return o, l, d, s

def entry_point(argv): flow_control_variables(int(argv[1])); return 0
def target(*args): return entry_point



All module globals are considered constants. Their binding must not be changed at run-time. Moreover, global (i.e. prebuilt) lists and dictionaries are supposed to be immutable: modifying e.g. a global list will give inconsistent results. However, global instances don’t have this restriction, so if you need mutable global state, store it in the attributes of some prebuilt singleton instance.

Control structures


All allowed, for loops restricted to builtin types, generators very restricted.



Range and xrange are identical. range does not necessarily create an array, only if the result is modified. It is allowed everywhere and completely implemented. The only visible difference to CPython is the inaccessibility of the xrange fields start, stop and step.



Run-time definition of classes or functions is not allowed.



Generators are supported, but their exact scope is very limited. you can’t merge two different generator in one control point.


Python exceptions are fully supported. For example, you can catch exceptions by the except keyword following a specific exception class.

def exceptions(x, y):
        n = x / y
    except ZeroDivisionError:
        print "division by zero"

def entry_point(argv):
    exceptions(int(argv[1]), int(argv[2]))
    return 0

def target(*args): return entry_point
if __name__ == "__main__": import sys; entry_point(sys.argv)

You can also use the raise keyword to raise exceptions. The finally keyword is used to do some cleanup actions.

class B(Exception):

class C(B):

class D(C):

def exceptions():
    for cls in [B, C, D]:
            raise cls()
        except D:
            print("exception D")
        except C:
            print("exception C")
        except B:
            print("exception B")
            print("put clean-up actions here")

def entry_point(argv):
    return 0

def target(*args): return entry_point
if __name__ == "__main__": import sys; entry_point(sys.argv)


There is one special difference in the exception handling on “simple cases”. In RPython document, it says by default, code with no exception handlers does not raise exceptions. By supplying an exception handler, you ask for error checking. Without, you assure the system that the operation cannot fail. This rule does not apply to function calls: any called function is assumed to be allowed to raise any exception.


MesaPy added mandatory IndexError checks. Give some details here.