Skip to content

Commit 81229a8

Browse files
committed
Use gensym where appropriate.
Due to performance reasons, there are still places where it's better to use `object()`, if the human-readable label is not necessary. One place in particular that needs to be fast is `arity.resolve_bindings`, because memoizers must call it every time when handling an incoming call. Using `gensym` there leads to a significant performance hit in `fix`, noticeable in the tests (~4-5 seconds instead of 1-2 to run `test_fix.py`, reproducible not only on CPython, but also on PyPy3).
1 parent 66fdd70 commit 81229a8

5 files changed

Lines changed: 13 additions & 6 deletions

File tree

unpythonic/arity.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,14 @@
1616
import operator
1717

1818
from .dynassign import dyn, make_dynvar
19+
from .symbol import gensym
1920

2021
make_dynvar(resolve_bindings_tuplify=False)
2122

2223
try: # Python 3.5+
2324
from operator import matmul, imatmul
2425
except ImportError:
25-
NoSuchBuiltin = object()
26+
NoSuchBuiltin = gensym("NoSuchBuiltin")
2627
matmul = imatmul = NoSuchBuiltin
2728

2829
class UnknownArity(ValueError):
@@ -379,7 +380,7 @@ def f(a):
379380

380381
# https://docs.python.org/3/reference/compound_stmts.html#function-definitions
381382
# https://docs.python.org/3/reference/expressions.html#calls
382-
unassigned = object() # gensym
383+
unassigned = object() # gensym("unassigned"), but object() is much faster and we don't need the label.
383384
slots = [unassigned for _ in range(len(params))] # yes, varparams too
384385

385386
# fill from positional arguments

unpythonic/ec.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@
3131
from functools import wraps
3232

3333
from .regutil import register_decorator
34+
# from .symbol import gensym
3435

3536
def escape(value, tag=None, allow_catchall=True):
3637
"""Alias for `throw`, for backward compatibility.
@@ -263,7 +264,7 @@ def inner():
263264
Similar usage is valid for named functions, too.
264265
"""
265266
# Create a process-wide unique id to tag the ec:
266-
anchor = object()
267+
anchor = object() # gensym("anchor"), but object() is much faster and we don't need the label.
267268
uid = id(anchor)
268269
# Closure property important here. "ec" itself lives as long as someone
269270
# retains a reference to it. It's a first-class value; the callee could

unpythonic/lazyutil.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@
99

1010
from .regutil import register_decorator
1111
from .dynassign import make_dynvar
12+
from .symbol import gensym
1213

1314
# HACK: break dependency loop llist -> fun -> lazyutil -> collections -> llist
1415
#from .collections import mogrify
1516
_init_done = False
16-
jump = object() # gensym, nothing else "is" this
17+
jump = gensym("jump")
1718
def _init_module(): # called by unpythonic.__init__ when otherwise done
1819
global mogrify, jump, _init_done
1920
from .collections import mogrify

unpythonic/llist.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
from .fold import foldr, foldl
1313
from .it import rev
1414
from .singleton import Singleton
15+
# from .symbol import gensym
1516

1617
# explicit list better for tooling support
1718
_exports = ["cons", "nil",
@@ -250,7 +251,7 @@ def __eq__(self, other):
250251
if isinstance(other, cons):
251252
try: # duck test linked lists
252253
ia, ib = (LinkedListIterator(x) for x in (self, other))
253-
fill = object() # essentially gensym
254+
fill = object() # gensym("fill"), but object() is much faster and we don't need the label.
254255
for a, b in zip_longest(ia, ib, fillvalue=fill):
255256
if a != b:
256257
return False

unpythonic/net/server.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@
145145

146146
from ..collections import ThreadLocalBox, Shim
147147
from ..misc import async_raise, namelambda
148+
from ..symbol import sym
148149

149150
from .util import ReuseAddrThreadingTCPServer, socketsource
150151
from .msg import MessageDecoder
@@ -228,7 +229,9 @@ def halt(doit=True):
228229
server_print(msg)
229230

230231
_bg_results = {}
231-
_bg_running, _bg_success, _bg_fail = [object() for _ in range(3)]
232+
_bg_running = sym("_bg_running")
233+
_bg_success = sym("_bg_success")
234+
_bg_fail = sym("bg_fail")
232235
def bg(thunk):
233236
"""Spawn a thread to run `thunk` in the background. Return the thread object.
234237

0 commit comments

Comments
 (0)