Collapse Literals¶
Collapse literal operations in code to their results, e.g. x = 1 + 2
gets converted to x = 3
.
For example:
@pragma.collapse_literals
def f(y):
x = 3
return x + 2 + y
# ... Becomes ...
def f(y):
x = 3
return 5 + y
This is capable of resolving expressions of numerous sorts:
- A variable with a known value is replaced by that value
- An iterable with known values (such as one that could be unrolled by
pragma.unroll()
), if indexed, is replaced with the value at that location - A unary, binary, or logical operation on known values is replaced by the result of that operation on those values
- A if/elif/else block is trimmed of options that are known at decoration-time to be impossible. If it can be known which branch runs at decoration time, then the conditional is removed altogether and replaced with the body of that branch
If a branch is constant, and thus known at decoration time, then only the correct branch will be left:
@pragma.collapse_literals
def f():
x = 1
if x > 0:
x = 2
return x
# ... Becomes ...
def f():
x = 1
x = 2
return 2
This decorator is actually very powerful, understanding any definition-time known collections, primitives, or even dictionaries. Subscripts are resolved if the list or dictionary, and the key into it, can be resolved. Names are replaced by their values if they are not containers (since re-writing a container, such as a tuple or list, could duplicate object references). Functions, such as len
and sum
can be computed and replaced with their value if their arguments are known.
Only primitive types are resolved, and this does not include iterable types. To control this behavior, use the collapse_iterables
argument. Example:
v = [1, 2]
@pragma.collapse_literals
def f():
yield v
# ^ nothing happens ^
@pragma.collapse_literals(collapse_iterables=True)
def f():
yield v
# ... Becomes ...
def f():
yield [1, 2]
There are cases where you don’t want to collapse all literals. It often happens when you have lots of global variables and long functions, or if you want to apply different pragma patterns to different parts of the function. Fine control is possible with the explicit_only
argument. When True, only explicit keyword arguments and the value of the function_globals
argument (itself a dictionary) are collapsed.
pragma
is capable of logical and mathematical deduction, meaning that expressions with unknowns can be collapsed if the known elements determine the result. For example, False and anything
is logically equivalent to False
. True or anything
is always True
. Mathematical: anything ** 0
-> 1
. 0 * anything
-> 0
.
Todo
Always commit changes within a block, and only mark values as non-deterministic outside of conditional blocks
Todo
Support list/set/dict comprehensions
Todo
Attributes are too iffy, since properties abound, but assignment to a known index of a known indexable should be remembered