def METHOD_NAME(a, b):
    "Replacement for cmp(a, b), removed in Python 3, for Expr objects."
    # Modelled after pre_traversal to avoid recursion:
    left = [(a, b)]
    while left:
        a, b = left.pop()
        # First sort quickly by type code
        x, y = a._ufl_typecode_, b._ufl_typecode_
        if x != y:
            return -1 if x < y else 1
        # Now we know that the type is the same, check further based
        # on type specific properties.
        if a._ufl_is_terminal_:
            c = _terminal_cmps[x](a, b)
            if c:
                return c
        else:
            # If the hash is the same, assume equal for the purpose of
            # sorting.  This introduces a minor chance of
            # nondeterministic behaviour, just as with MultiIndex.
            # Although collected statistics for complicated forms
            # suggest that the hash function is pretty good so there
            # shouldn't be collisions.
            # if hash(a) == hash(b): # FIXME: Test this for performance improvement.
            #    return 0
            # Delve into subtrees
            aops = a.ufl_operands
            bops = b.ufl_operands
            # Sort by children in natural order
            for (r, s) in zip(aops, bops):
                # Skip subtree if objects are the same
                if r is s:
                    continue
                # Append subtree for further inspection
                left.append((r, s))
            # All children compare as equal, a and b must be
            # equal. Except for...  A few types, notably ExprList and
            # ExprMapping, can have a different number of operands.
            # Sort by the length if it's different. Doing this after
            # sorting by children because these types are rare so we
            # try to avoid the cost of this check for most nodes.
            x, y = len(aops), len(bops)
            if x != y:
                return -1 if x < y else 1
    # Equal if we get out of the above loop!
    return 0