On 07/10/2011 09:13 PM Laura Creighton wrote:
What do we want to happen when somebody -- say in a C extension -- takes the id of an object that is scheduled to be removed when the gc next runs?
IMO taking the id should increment the object ref counter and prevent the garbage collection, until the id value itself is garbage collected. The obvious way would be to make id an object that keeps a reference to the object whose id it represents. See below[1] for an example (just for discussion illustration).
Of course in low level access, conventions of ownership can sometimes safely optimize away actual ref incr/decr, but it sounds like your example proposes "taking an id" after ref count has gone to zero. That's like doing a reinterpret_cast to integer of a malloc pointer after the area's been freed, and expecting it to mean something. It should be an enforced nono, if you ask me. The example id attempts to make all equivalent immutables of the same type have the same id, by taking advantage of dict's key comparison properties and the .setdefault method. to get something like the current, with just the object reference to make an id hold its object, use IdHolder in place of Id. But then you can get all kinds of ids for the same immutable value, as with the old id. _______________________________________________________________________________ # idstuff.py -- a concept-exploring toy re "id" # 2011-07-10 22:58:46 bokr # class Id(object): refval = id # old id function objcache = {} # to store typed immutables for ref to first of equal-valued encountered # and using old id of the first as id for all of same type and equal value. def __init__(self, obj): self.obj = obj def id(self): so=self.obj if type(so) in (int,float,bool,tuple,str,unicode): # etc? t = (type(so), so) return self.refval(self.objcache.setdefault(t, t)[1]) else: return self.refval(so) # as now? XXX what is abstract meaning of id(some_mutable)? def __eq__(self, other): if type(self) != type(other): raise TypeError('Id instances can only be compared with each other,' 'not to "%s" instances.'% type(other).__name__) tobj=type(self.obj) tother=type(other.obj) if tobj != tother: return False return self.id() == other.id() def __repr__(self): return '<Id(%r)==%i vs old %i>'%(self.obj, self.id(), self.refval(self.obj)) def __str__(self): return '<Id(%s)>'%(self.obj,) class IdHolder(object): refval = id # old id function def __init__(self, obj): self.obj = obj self.id = self.refval(obj) def __eq__(self, other): if type(self) != type(other): raise TypeError('IdHolder instances can only be compared with each other,' ' not to "%s" instances.'% type(other).__name__) return self.id == other.id def __repr__(self): return '<IdHolder(%r)==%i>'%(self.obj, self.id) def __str__(self): return '<IdHolder(%s)>'%(self.obj,) _______________________________________________________________________________ Python 2.7.2 (default, Jul 8 2011, 23:38:53) [GCC 4.1.2] on linux2 Type "help", "copyright", "credits" or "license" for more information. >>> oldid=id >>> from ut.idstuff import IdHolder as id >>> from ut.idstuff import Id as idk # with caching for equal (type,value) immutables >>> oldid(2000),oldid(2000),oldid(20*100) (136189164, 136189164, 136189176) >>> id(2000),id(2000),id(20*100) # no k cacheing (<IdHolder(2000)==136189164>, <IdHolder(2000)==136189164>, <IdHolder(2000)==136189212>) >>> idk(2000),idk(2000),idk(20*100) # with k cacheing (<Id(2000)==136189236 vs old 136189236>, <Id(2000)==136189236 vs old 136189236>, <Id(2000)==136189236 vs old 136189140>) >>> >>> oldid([]),oldid([]) # dangling pointer value returned (3083895948L, 3083895948L) >>> id([]),id([]) # pointer kept live (<IdHolder([])==3083895948>, <IdHolder([])==3083896108>) >>> idk([]),idk([]) # pointer kept live, constant caching n/a (<Id([])==3083784300 vs old 3083784300>, <Id([])==3083896908 vs old 3083896908>) >>> Have fun ;-) Regards Bengt Richter
Laura
= _______________________________________________ pypy-dev mailing list pypy-dev@python.org http://mail.python.org/mailman/listinfo/pypy-dev