Skip to content

Instantly share code, notes, and snippets.

@ncoghlan
Last active February 16, 2018 02:10
Show Gist options
  • Save ncoghlan/a1b0482fc1ee3c3a11fc7ae64833a315 to your computer and use it in GitHub Desktop.
Save ncoghlan/a1b0482fc1ee3c3a11fc7ae64833a315 to your computer and use it in GitHub Desktop.
PEP 505 alternative: the "?it" symbolic reference

Using ?it as a statement local symbolic reference

Core concept

  • (?it=expr) is a new atomic expression for an "it reference binding"
  • subsequent subexpressions (in execution order) can reference the bound subexpression using ?it (an "it reference")
  • ?it is reset between statements, including before entering the suite within a compound statement (if you want a persistent binding, use a named variable)
  • for conditionals, put the reference binding in the conditional, as that gets executed first
  • to avoid ambiguity, especially in function calls (where it could be confused with keyword argument syntax), the parentheses around reference bindings are always required

Examples

None-aware attribute access:

value = ?it.strip()[4:].upper() if (?it=var1) is not None else None

None-aware subscript access:

value = ?it[4:].upper() if (?it=var1) is not None else None

None-coalescense:

value = ?it if (?it=var1) is not None else ?it if (?it=var2) is not None else var3

NaN-coalescence:

value = ?it if not math.isnan((?it=var1)) else ?it if not math.isnan((?that=var2)) else var3

Conditional function call:

value = ?it() if (?it=calculate) is not None else default

Avoiding repeated evaluation of a comprehension filter condition:

filtered_values = [?it for x in keys if (?it=get_value(x)) is not None]

Avoiding repeated evaluation for range and slice bounds:

range((?it=calculate_start()), ?it+10)
data[(?it=calculate_start()):?it+10]

Avoiding repeated evaluation in chained comparisons:

value if (?it=lower_bound()) <= value < ?it+tolerance else 0

Avoiding repeated evaluation in an f-string:

print(f"{?it=get_value()!r} is printed in pure ASCII as {?it!a} and in Unicode as {?it}"

A possible future extension would then be to pursue PEP 3150, treating the nested namespace as an it reference binding, giving:

sorted_data = sorted(data, key=?it.sort_key) given ?it=:
    def sort_key(item):
        return item.attr1, item.attr2

(A potential added bonus of that spelling is that it may be possible to make "given ?it=:" the syntactic keyword introducing the suite, allowing "given" itself to continue to be used as a variable name)

Alternative spellings considered

  • (?=expr) (binding) and ? (reference): cryptic to read, no obvious pronunciation
  • (?expr) (binding) and ?? (reference): cryptic to read, no obvious pronunciation
  • (that=expr) (binding) and that (reference): looks too much like function call keyword arguments and ordinary variable references
  • (?that=expr) (binding) and ?that (reference): that was the first pronoun considered, but the proposal switched to it to make the boilerplate lighter
@ncoghlan
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment