|
From: Samuele P. <ped...@bl...> - 2002-01-03 18:48:54
|
Hi, As you might or might not know http://sourceforge.net/tracker/index.php?func=detail&aid=222789&group_id=12867& atid=112867 __builtin__.id is broken in jython. This is a long standing bug, although mostly ignored. Recently I have been following closely the anygui project (www.anygui.org), some of their code has shown me that there are indeed natural python idioms that rely on a working id. Yes there are workarounds but for prototyping, people coming from python and porting I would prefer to say that id under jython does not give top-notch performance than to confess that it is broken. So maybe it is time to at least try to fix this. Java 1.2 has weak refs and this helps. What follows at the end of the message is an implementation of a non-broken id. Discussion - The python code purpose is to show the logic, the final version must be in java and use java weak-refs. The python version performance is abysmal, that's clear. The python version is not completely thread-safe, this will be solved for the java code. The java version will be slower that the current code, but that's broken so this comparison makes little sense <wink>. This code will be used for java > 1.2. For previous versions we will continue to use identityHashCode. - Yes it does consume memory, although only for the objects for which you ask the id. The other solution is to put the id inside each PyObject but for PyJavaInstances we still need the table because their identity is just simulated. Yes, we could also use a mixed approach. - Do we need the _reuse list? No, it's probably just hyper-defensive programming. The java code could just use a ever-increasing long counter. If the feeback converges ;) I will prepare a final patch. regards, Samuele Pedroni. # works as full substitute of id # under jython, where it is legal # to create weak-refs to ints, etc. from weakref import ref class _WeakIdWrapper: def __init__(self,v): self._hash = id(v) # old broken id, i.e. identityHashCode self._ref = ref(v) def with_callback(self,v,callback): self._callback = callback self._ref = ref(v,self._trigger_callback) def __eq__(self,o): if self is o: return 1 mine = self._ref() o = o._ref() if mine is None or o is None: return 0 return mine is o def _trigger_callback(self,refign): self._callback(self) def __hash__(self): return self._hash def __call__(self): return self._ref() _table = {} # the idea is to mimic a # a memory allocation policy # so _reuse, the approach should # deal with long running processes # vs ids exauhaustion _reuse = [] def _remove(wr): global _table,_u,_reuse u = _table[wr] del _table[wr] if _table: _reuse.append(u) else: # heuristic _reuse = [] _u = 0 _u = 0 # id substitute def _weakid(v): if v is None: return 0 global _table table = _table wr = _WeakIdWrapper(v) try: return table[wr] except: global _u,_remove if _reuse: u = _reuse.pop() else: _u += 1 u = _u wr.with_callback(v,_remove) table[wr] = u return u |