Thread: [Pyobjc-dev] Bridging strings from Python to other languages
Brought to you by:
ronaldoussoren
From: Bill B. <bb...@co...> - 2003-02-05 04:56:02
|
[This is a continuation of the thread that Just mentions below -- "NSString & mutability". I finally had a chance to write enough code to figure out where the walls were that I kept bloodying my head against. I believe I also came up with a more constructive way to think about this whole problem. More below -- the end of the 'bridging strings' section contains a series of what I believe are issues with the current Python implementation that should/may/could be addressed in a future version] On Tuesday, Feb 4, 2003, at 22:13 US/Eastern, Just wrote on python-dev: > (The use case is this. The PyObjC project marries Objective-C with > Python. This is cool as it gives us direct access to almost all of > Cocoa, the native OSX GUI interface. However, Cocoa defines its own > string type and for reasons that are waaay beyond the scope of this > post > (check the archives of the pyobjc-dev list if you're really really > interested; see a recent thread called "NSString & mutability") it > appears a bad idea to _convert_ these strings to Python unicode > strings. > So we need to wrap them. Yet they should work as much like unicode > strings as possible...) Let me rephrase the problem in slightly different terms. This will be long winded-- skip down to the 'bridging strings' section if you don't want to go through the initial discussion of the challenges of bridging two runtimes... In creating a bridge between Python and other languages-- in this case, Objective-C-- the general goal is to provide seamless connectivity between the two runtime environments. That is, you want to have a proxy to objects or structures found in the 'alien' runtime available in the 'native' runtime in a fashion that makes the proxy convenient to use. Generally, this means that the proxy should act as much like the 'native' runtime up to the point where it starts to obfuscate the behavior of the 'alien' runtime. While a decent bridging and proxying mechanism can make "crossing the bridge" easy to do, one can never avoid the fact that there really is a bridge and on the other side there really is an 'alien' runtime. Now-- there are a number of different ways to proxy objects/structures between the two runtimes: - pure proxy: the object/structure to be bridged is represented by a proxy that handles all requests for information or invocation of functions/methods by converting the request/invocation into a form that can be understood on the other side of the bridge. Example -- the following creates a python native proxy to the alien Objective-C NSMutableArray instance (ignore that it really creates an NSCFArray-- that is an internal-to-Foundation implementation detail that is irrelevant). The expression 'a.count()' actually causes the 'count' Objective-C method to be invoked through the proxy a: >>> from Foundation import * >>> a = NSMutableArray.array() >>> type(a) <objective-c class NSCFArray at 0x466d0> >>> a.count() 0 >>> len(a) 0 The len(a) is just a demonstration of how far the proxying can go by defining the appropriate internal(?) attributes on the proxy. - pure conversion: the object/structure to be bridged is converted to the native type as it crosses the bridge. Example -- the NSString is currently bridged to the Python String class such that string instances are converted to their native types as they cross the bridge [at least, this is the case in CVS -- I now have a proxy class that can wrap a Python PyString/PyUnicode instance and present it is a standard NSString instance on the ObjC side. Avoids lots of unnecessary data copying when going from Python->Objective-C, but it needs a bunch of cleanup before I commit.]: In the following, I create a new Objective-C NSString instance and assign it to 's'. What results is a copy of the contents of the NSString instnace shoved into a normal Python string. >>> s = NSString.stringWithString_("Foobar") >>> type(s) <type 'str'> - mixed conversion/proxy: this is a suboptimal case. It generally converts to a native type in one direction, but potentially not in the other or not fully. Example -- NSNumber is currently in this category. It should change eventually, but there are issues to deal with: >>> a = NSArray.arrayWithObject_(1) >>> a[0] <NSCFNumber objective-c instance 0x6704b0> >>> a[0] + 1 2 --- One of the key challenges is that proxying effectively causes two references to any given object to exist; the native object reference and the 'alien' reference through the proxy. Care must be taken to ensure that a single reference on either side of the bridge is enough to preserve both components of the hunk of data while also ensuring that the existence of a proxy without references does not prevent the item from being collected [may sound confusing: consider the situation where a Python class is subclassed in the alien environment or vice-versa -- you effectively end up with instances that have part of their implementation in one runtime and the other part in the other runtime. It can lead to issues.]. In general, these kinds of issues can be worked through by leveraging mechanisms such as weak references. By providing a callback on the finalization of an object, it is possible to ensure that the alien-to-python component of the instance is destroyed, as well. A final challenge is that sometimes an object's type or contents are completely irrelevant to a piece of code. It is the object reference itself that is meaningful. In these situations, if an object is passed across the bridge and back, what should come back really should be what went across in the first place-- if not, the contents may have been preserved, but the object's original identity has been lost. Sometimes an object is just an object. --- Strings provide a particular set of challenges in that no two runtime environments present exactly the same set of features in their string handling API, yet every runtime has some kind of a string API and, invariably, that API is very much at the core of the runtime. The addition of Unicode to every string API over the last decade+ has not made things any simpler. In python, strings are immutable and can encapsulate non-unicode data. A separate unicode-- also immutable-- type is provided to encapsulate unicode data, but the standard string type can also encapsulate unicode data in certain circumstances [at least, it appears that PyString will happily consume and represent UTF8]. In Objective-C [and other languages], there is a single String class that can encapsulate both ASCII and unicode data in many different encodings. Furthermore, there is a subclass of String that provides additional mutability API -- an instance of the mutable string class can have its contents changed by the developer while the identity of the object remains the same (unlike python where appending "b" to "a" results in a new string "ab"). To further complicate matters, most typed languages support the concept of 'upcasting' -- that is, of casting a particular instance to actually be an instance of a superclass. For Objective-C, it can mean that a method that is declared as returning an immutable string or array actually returns a mutable string or array instance -- as long as the developer pays attention to the compiler warnings and doesn't do any stupid casting of their own, everything is fine. Java offers similar casting "features". - bridging strings - So, how to bridge strings in such an environment? In all cases, we can [fortunately] assume that strings pass across the bridge in one of a few choke points in the code -- that there is always a location to add a little bit of logic with which to help bridge the string [or any other random object]. The goal is to bridge strings in a fashion such that (not really in order of importance): (1) only one hunk of memory is used to contain the data within the string (2) conversion is kept to a minimum, if present at all, because strings will be passed back-and-forth across the bridge very frequently (3) identity is maintained; pass a string with id() 7570720 from Python into the alien runtime and subsequently from the alien runtime back into python and the same string instance with id() 7570720 really should come back (4) 'alien' string specific API can still be used; the Objective-C NSString provides a very rich API, including localization features that are not available in pure python. For Python->Objective-C, bridging strings has proven to be fairly easy. (1), (2), and (4) are quite straightforward. (3) is not done yet. For Objective-C->Python, bridging strings is not so easy. The difficulty is compounded by certain features of the Python string/unicode APIs. (1) is pretty easy -- the challenge is to figure out which API to call on the Python side such that the resulting Python object does not copy and re-encode the data. If that is unavoidable, the cost of encoding or conversion (2) should be minimized [hopefully with a cache so that cost of conversion is paid once, then never again for immutable string instances]. There is also the ongoing challenge of determining when to use the PyString vs. PyUnicode APIs; it seems that unicode objects are not welcome everywhere that string objects are? (4) is actually quite easy and has been available for some time through the use of unbound methods. However, the current implementation in CVS will always cause the python string to be converted to an NSString, the method invoked, and then the result-- if any and if a string-- is converted back to a python string. (3) is not so easy-- at least, not from what I have determined so far. Most of the issues seem to be due to limitations in Python (which is really just another way of saying "I don't know enough to approach this problem from the right direction"): - can't use weakref because one can't have a weak reference to a string or unicode object. This means that a callback when a string ref is finalized on the python side is not possible. It also means that creating a hash between ObjC string instances and Python string instances can't be done without using strong references, thereby creating the potential for leaking memory. - can't subclass string (but can unicode) to provide a class that acts exactly like a regular string while containing a reference to the foreign string object. There doesn't appear to be anywhere to hide a hunk of data in the string instance, either. - can't use the character buffer APIs because a character buffer cannot be used consistently throughout the python APIs in the same places as a string. Using str() to turn a char buffer into a string violates (1) [and doesn't make much sense anyway]. End result -- it is very difficult to preserve the association between an alien string instance and a PyString instance consistently. Even if PyString instances provide very thorough and consistent hashing behavior where two strings with the same contents always hash the same, the same cannot be said of all alien environments. Even when it is true, there are cases where the developer may be relying on the identity of the object to not change outside of their control. Mutable strings obviously present issues of their own, but they are not particularly relevant to discussion on python-dev outside of how future development might make the support of such common idiosyncrasies a bit more straightforward. Ideally, one could have an object on the python side that looks/feels/smells like a string instance, but whose contents may change. This creates any number of exciting problems. To further compound problems, anything that is declared as returning an NSString *may* return an NSMutableString at whim. It doesn't happen often, but when it does, if the handling of mutable vs. immutable strings is too radically different, it'll cause code to blow up in highly unexpected and very difficult to debug ways. Rambling on.... b.bum |
From: Guido v. R. <gu...@py...> - 2003-02-05 15:53:33
|
Hi Bill, I've read though the end of your post, and while I appreciate the problem, I have little help to offer. It's not even clear whether you're asking for changes to Python or simply a hint as to how to write your bridge. To me, it seems that the crux is your requirement > (3) identity is maintained; pass a string with id() 7570720 from > Python into the alien runtime and subsequently from the alien runtime > back into python and the same string instance with id() 7570720 really > should come back In my experience almost no Python code depends on this property, and it seems to be the most problematic one. So why is this a requirement? If you can live with only using Unicode strings (even when all they contain is ASCII or Latin-1 values), I think subclassing Unicode might be the way to go. I don't have time to dig deeper into this. But if you think a small change to Python can make life easier for you, I expect we'll be happy to implement it, as long as it doesn't make life harder for Python developers. --Guido van Rossum (home page: http://www.python.org/~guido/) |
From: Bill B. <bb...@co...> - 2003-02-05 20:28:14
|
On Wednesday, Feb 5, 2003, at 10:52 US/Eastern, Guido van Rossum wrote: > In my experience almost no Python code depends on this property, and > it seems to be the most problematic one. So why is this a > requirement? Because we are using Python to glue together other object oriented frameworks-- Apple's and third party's-- for which we do not have control over said behavior. Sometimes an object is just an object and those frameworks insist on the same object-- same identifier/address-- coming out that went in. As Just pointed out, my original example wasn't as clear as it could have been. If a String object comes out of the alien-to-python world and is later sent from python back into the alien-to-python runtime, the same String object-- the same id()-- must be sent back. > If you can live with only using Unicode strings (even when all they > contain is ASCII or Latin-1 values), I think subclassing Unicode might > be the way to go. Right. I believe that is the path will we go down. > I don't have time to dig deeper into this. But if you think a small > change to Python can make life easier for you, I expect we'll be happy > to implement it, as long as it doesn't make life harder for Python > developers. I can think of a couple of changes to Python that would be potentially quite helpful in this situation. Specifically: - ability to have weak references to string objects [and unicode objects]. Since we can make arbitrary object associations and re-associations when crossing the bridge between environments, I believe weakref would allow us to maintain a reference map as long as we could grab the 'string is now going away' callback to update the weakref map when the string is deallocated - ability to subclass string objects or the ability to add a hunk of data-- the reference to the 'alien' string object-- to any string object. Either one would work equally as well... whether or not they are easy to do, I have not a clue. b.bum |
From: Guido v. R. <gu...@py...> - 2003-02-05 21:28:52
|
> On Wednesday, Feb 5, 2003, at 10:52 US/Eastern, Guido van Rossum wrote: > > In my experience almost no Python code depends on this property, and > > it seems to be the most problematic one. So why is this a > > requirement? [BBum] > Because we are using Python to glue together other object oriented > frameworks-- Apple's and third party's-- for which we do not have > control over said behavior. > > Sometimes an object is just an object and those frameworks insist on > the same object-- same identifier/address-- coming out that went in. > > As Just pointed out, my original example wasn't as clear as it could > have been. If a String object comes out of the alien-to-python world > and is later sent from python back into the alien-to-python runtime, > the same String object-- the same id()-- must be sent back. Ah. I still don't know what you call "alien" and what you call "native". But I think that I understood your original example as going the other direction (Python -> ObjC -> Python) while the issue really is ObjC -> Python -> ObjC. > > If you can live with only using Unicode strings (even when all they > > contain is ASCII or Latin-1 values), I think subclassing Unicode might > > be the way to go. > > Right. I believe that is the path will we go down. > > > I don't have time to dig deeper into this. But if you think a small > > change to Python can make life easier for you, I expect we'll be happy > > to implement it, as long as it doesn't make life harder for Python > > developers. > > I can think of a couple of changes to Python that would be potentially > quite helpful in this situation. > > Specifically: > > - ability to have weak references to string objects [and unicode > objects]. Since we can make arbitrary object associations and > re-associations when crossing the bridge between environments, I > believe weakref would allow us to maintain a reference map as long as > we could grab the 'string is now going away' callback to update the > weakref map when the string is deallocated Would you be okay with only weak refs to unicode objects? Either way, you have to start by submitting a patch (referring to this thread). > - ability to subclass string objects or the ability to add a hunk > of data-- the reference to the 'alien' string object-- to any string > object. You can do that in C, if you know how. The trick is to set tp_itemsize to 4 bytes extra, and then index from the end (rounding down). See how _PyObject_GetDictPtr() works when the dict offset is negative (in practice it will always be -4). > Either one would work equally as well... whether or not they are easy > to do, I have not a clue. Who knows. --Guido van Rossum (home page: http://www.python.org/~guido/) |
From: Just v. R. <ju...@le...> - 2003-02-05 19:32:35
|
[keeping python-dev out of this] Bill Bumgarner wrote: > (3) identity is maintained; pass a string with id() 7570720 from > Python into the alien runtime and subsequently from the alien runtime > back into python and the same string instance with id() 7570720 > really should come back I was going to say (but Guido beat me to it ;-): from a *Python* perspective this is an absolutely silly requirement. But it's also the exact opposite of what you said earlier: that identity sometimes matters in *ObjC*. You mentioned NSMapTable, but didn't answer my question how the semantics of NSMapTable are a) visible from Python and b) _relevant_ to Python coders. That said, a subclass of unicode that is a conversion of as well as holds a reference to the original NSString (as Bob Ippolito suggested) perhaps wouldn't be so bad after all, at least for immutable strings. For immutable strings things still get fishy. Hm, here's a quick idea: I see that the PyUnicodeObject struct uses a seperately allocated buffer as the backing store (as opposed to "normal" strings, where the storage is part of the object itself). This means that (at least in theory) can we actually make a _mutable_ subclass of unicode! Provided we make sure no hash can be taken, this might actually fly. Hm, maybe I shouldn't have left python-dev out of this after all... (This would abviously still be depending on implementation details: some strings are hashable and others are not, and _where_ these differences appear may change at any time :-( ) Just |
From: Bill B. <bb...@co...> - 2003-02-05 19:49:59
|
On Wednesday, Feb 5, 2003, at 13:52 US/Eastern, Just van Rossum wrote: > [keeping python-dev out of this] > Bill Bumgarner wrote: >> (3) identity is maintained; pass a string with id() 7570720 from >> Python into the alien runtime and subsequently from the alien runtime >> back into python and the same string instance with id() 7570720 >> really should come back > I was going to say (but Guido beat me to it ;-): from a *Python* > perspective this is an absolutely silly requirement. But it's also the > exact opposite of what you said earlier: that identity sometimes > matters > in *ObjC*. You mentioned NSMapTable, but didn't answer my question how > the semantics of NSMapTable are a) visible from Python and b) > _relevant_ > to Python coders. You're right-- it is silly. I should have flipped the example around: Pass a string with (id) (0x1234) from ObjC into Python and back out again and the (id) should remain the same. It may be a silly requirement for strings, but it is not a silly requirement for objects -- a string is just another object and there are those contexts, more common in spastically optimized C-derived compiled languages than in interpreted languages, where the class is irrelevant and the identity of the object is what matters. The Python developer will never see NSMapTable, unless we bridge that particular API (not much point, but maybe some day). But that doesn't mean an NSMapTable will not be in use in the underlying frameworks. NSMapTable is [very likely -- it used to be, but they may have switched to other similar CF* APIs by now -- same problem] used within the AppKit implementation. Any of the various APIs that provide map like access to internal state may very likely use an NSMapTable. If they don't know, they may in the future. Example -- NSTableView allows one to apply an arbitrary object, class irrelevant, to be used as a table column identifier: - (int)columnWithIdentifier:(id)identifier; - (NSTableColumn *)tableColumnWithIdentifier:(id)identifier; Corresponding API on NSTableColumn: - (void)setIdentifier:(id)identifier; - (id)identifier; "Identiefier" with an (id) type means something very different than "Name" with an (NSString*) type. In particular, it means that the identity of the object is very likely the key to identifying table columns. > That said, a subclass of unicode that is a conversion of as well as > holds a reference to the original NSString (as Bob Ippolito suggested) > perhaps wouldn't be so bad after all, at least for immutable strings. > For immutable strings things still get fishy. 'For *mutable* strings things still get fishy.'? Yes. They certainly do. Head hurts. Right. Off the top of your head, how much of Python breaks when unicode objects are passed into various random API vs. 'normal' string instances? I have no idea and am hoping the number is small. Would Bob's suggestion work in that it proxies unicode enough such that an instance of his class will still behave correctly in most situations? Any idea of the magnitude of breakage? I'm going to plug in Bob's implementation into the buffer_from_string() function I wrote. If it does work, it would probably be useful to convert it into C land simply because it'll be used so often. > Hm, here's a quick idea: > I see that the PyUnicodeObject struct uses a seperately allocated > buffer > as the backing store (as opposed to "normal" strings, where the storage > is part of the object itself). This means that (at least in theory) can > we actually make a _mutable_ subclass of unicode! Provided we make sure > no hash can be taken, this might actually fly. Hm, maybe I shouldn't > have left python-dev out of this after all... > (This would abviously still be depending on implementation details: > some > strings are hashable and others are not, and _where_ these differences > appear may change at any time :-( ) I would think it would be a matter of ensuring that the hash is not cached and is recalc'd anytime it is requested. We can do 'isDirty' type optimizations if it actually works. Obviously, a mutable string as a dictionary key is generally a Bad Idea. In the case of NSDictionary, I believe it makes an immutable copy of the inbound string. Since NSString's -copy is effectively implemented as... - copy { return [self retain]; } ... the cost of the "copy" for immutable strings is negligible. b.bum |
From: Just v. R. <ju...@le...> - 2003-02-05 21:23:48
|
Bill Bumgarner wrote: > Example -- NSTableView allows one to apply an arbitrary object, class=20 > irrelevant, to be used as a table column identifier: >=20 > - (int)columnWithIdentifier:(id)identifier; > - (NSTableColumn *)tableColumnWithIdentifier:(id)identifier; >=20 > Corresponding API on NSTableColumn: >=20 > - (void)setIdentifier:(id)identifier; > - (id)identifier; >=20 > "Identiefier" with an (id) type means something very different than=20 > "Name" with an (NSString*) type. In particular, it means that the=20 > identity of the object is very likely the key to identifying table=20 > columns. It seems that solving the mutable vs. immutable issue by means of a wrapper/proxy issue will also solve this one for NSStrings. However, the NSTableView doco has this to say: """ columnWithIdentifier:=20 - (int) columnWithIdentifier: (id) anObject=20 Returns the index of the first column in the receiver whose identifier is equal to anObject , when compared using isEqual: , or =AD1 if no columns are found with the specified identifier.=20 """ Note the "when compared using isEqual". So it appears the API isn't as broken as you suggest... Still, we write Python code. There will _always_ be Cocoa things that are hard or even impossible to do from Python. We have to make compromises, often choosing between "model Cocoa as closely as possible in Python" and "make Cocoa a pleasure to work with from Python". Unless there are serious flaws (such as with mutable strings), I think we should generally choose for convenience. One such compromise would be "when passing NSNumber instances across the bridge, the object identity will not be preserved". It is awfully silly to _wrap_ NSNumbers. And there's no NSMutableNumber, is there <0.5 wink>? We write in Python because it gives us a head-start compared to people using Obj-C or C or C++ or Java. Let's not hurt ourselves by sticking too close to theoretical correctness. > > That said, a subclass of unicode that is a conversion of as well as > > holds a reference to the original NSString (as Bob Ippolito > > suggested) perhaps wouldn't be so bad after all, at least for > > immutable strings. For immutable strings things still get fishy. >=20 > 'For *mutable* strings things still get fishy.'?=20 Yes, that was a brainfart. > Yes. They certainly do. Head hurts. >=20 > Right. Off the top of your head, how much of Python breaks when=20 > unicode objects are passed into various random API vs. 'normal' string=20 > instances?=20 That works reasonable well, and actually has a much greater chance of working well than creating our own string-like type or unicode-like type. However, there are objects and calls that are not unicode aware. Eg. writing a unicode string to a file currently only works if it only contains pure 7-bit ascii characters. (There is an encoding aware file object replacement available, but it needs to imported separately, see codecs.open()). We could wrap NSString instances in a str subclass or a unicode subclass depending on whether the NSString is 7-bit clean. There is little point (apart from simplicity) in _always_ using a unicode subclass, as they will cause the exact same surprises (as mentioned above). > I have no idea and am hoping the number is small. Since NSStrings can _always_ contain unicode, I think we should assume using unicode strings is fine. > Would Bob's suggestion work in that it proxies unicode enough such > that an instance of his class will still behave correctly in most > situations? Any idea of the magnitude of breakage? (Assuming you mean his suggestion to subclass unicode) I think this has a good chance of working really well. > > Hm, here's a quick idea: > > [creating a mutable subclass of unicode] >=20 > I would think it would be a matter of ensuring that the hash is not=20 > cached and is recalc'd anytime it is requested. We can do 'isDirty'=20 > type optimizations if it actually works. Doesn't work: it's a requirement (at least for Python dicts, but I think it's a generic hash table requirement) that an object's hash value doesn't change while it's used as a key. Hence only immutable objects are allowed as dict keys. (There's a minor exception to this: objects that don't define __eq__ (and/or __cmp__, I'm not sure about the exact details) can still be used as keys: they will be compared by id, and hash(suchAnObject) returns the same as id(suchAnObject.) > Obviously, a mutable string as a dictionary key is generally a Bad=20 > Idea. In the case of NSDictionary, I believe it makes an immutable=20 > copy of the inbound string. Since NSString's -copy is effectively=20 > implemented as... >=20 > - copy > { > return [self retain]; > } >=20 > .... the cost of the "copy" for immutable strings is negligible. It does still brings the dependency on implementation details to Python: _some_ NSStrings can be used as keys in Python dicts and others won't. Python doesn't do anything special to "inbound" keys, it simply barfs when the key isn't hashable. Shall we call this the "fragile mutability" syndrome? It's a darn ugly corner of Cocoa if you ask me :-(. Just |
From: Just v. R. <ju...@le...> - 2003-02-05 22:34:47
|
Just van Rossum wrote: > Python doesn't do anything special to "inbound" keys, it simply barfs > when the key isn't hashable. Here's an idea: we could propose a new protocol for dicts that would work like this: def __setitem__(self, key, value): if not hashable(key): if hasattr(key, "__immutablecopy__"): key = key.__immutablecopy__() else: raise TypeError, "unhashable key" ...insert value with key into dict... This might actually solve our problem nicely. Soonest for 2.3, though, and even then we need to hurry. Just |
From: Bill B. <bb...@co...> - 2003-02-05 22:37:53
|
That makes a lot of sense. In general, I would like to see Python move in the direction of supporting <character buffers> in an analagous/interchangeable fashion with <string>. This would make integration with external tools a lot easier. A part of that is doing exactly what you have indicated below -- when a string must be constant and there is a question as to whether or not the backing store for the string is mutable, provide a mechanism via which an immutable copy can be created. Nice. b.bum On Wednesday, Feb 5, 2003, at 17:34 US/Eastern, Just van Rossum wrote: > Just van Rossum wrote: > >> Python doesn't do anything special to "inbound" keys, it simply barfs >> when the key isn't hashable. > > Here's an idea: we could propose a new protocol for dicts that would > work like this: > > def __setitem__(self, key, value): > if not hashable(key): > if hasattr(key, "__immutablecopy__"): > key = key.__immutablecopy__() > else: > raise TypeError, "unhashable key" > ...insert value with key into dict... > > This might actually solve our problem nicely. Soonest for 2.3, though, > and even then we need to hurry. > > Just |
From: Just v. R. <ju...@le...> - 2003-02-05 22:52:32
|
Bill Bumgarner wrote: > In general, I would like to see Python move in the direction of > supporting <character buffers> in an analagous/interchangeable fashion > with <string>. This would make integration with external tools a lot > easier. To a large extent this already works for 8-bit strings, but I don't see an easy solution for unicode that doesn't depend on a specific format of the backing store. I'll try to write a proposal regarding __immutablecopy__, which btw. needs a __temporaryimmutable__ counterpart for efficient membership testing (this would return a thin wrapper what would compare and hash equally to the real thing, yet no copy is made). This latter idea I just saw in sets.py: neat. Just |