From: William S F. <ws...@fu...> - 2008-01-21 22:01:07
|
Josh Cherry wrote: > > > On Sat, 19 Jan 2008, William S Fulton wrote: > >> Josh Cherry wrote: >>> >>> Why restrict things to Python lists and tuples? If somebody writes a >>> Python type that can be indexed or iterated over, there is utility in >>> accepting it. At least the argument can be made, and that's how >>> things often wind up working in Python. On the other hand, if this >>> feature is omitted, the caller can pass list(x) rather than x. >> >> SWIG allows customisation. If a user wants to write their own >> sequence, then they can customise the typecheck typemap. I think the >> default should favour performance over more esoteric usage. Plus it >> will improve the bogus shadow warnings. > > I'm not talking (necessarily) about sequence types that the SWIG user > writes. I'm talking about any sequence types that an ultimate user of > the SWIG-generated library might want to use. This could include things > written by that user (who may have never even heard of SWIG), things in > third-party modules, or sequences in the standard Python distribution > that aren't lists or tuples. I'll give you two examples of the last: > >>>> xr = xrange(10) >>>> type(xr) > <type 'xrange'> >>>> example.vects(xr) >>>> >>>> import array >>>> ar = array.array('l', [42, 6, 7]) >>>> type(ar) > <type 'array.array'> >>>> example.vects(ar) > > Those calls to example.vects succeed because the stl support deals with > any sequence with the right kind of elements. If you changed it to > accept only lists and tuples, those calls would fail. Users would still > be able to do, e.g., > >>>> example.vects(list(ar)) > > so it's not the end of the world, but I wanted to be clear on what would > be lost. Lots of things in Python work with sequences in an abstract > manner. You can do > >>>> sorted(ar) > [6, 7, 42] > > not because sorted() was written specifically to deal with the array > type, but because it was written to deal with any sequence. > Okay, so if this is standard behaviour for Python we shouldn't limit the conversion to just Lists and Tuples, except we should not attempt to convert SWIG wrapped objects as the C++ wrapped code has the type checker. >>>> This means that if an overloaded method contains one of the STL >>>> containers, an >>>> attempt is made to convert the elements in any object that has a >>>> __getitem__. >>>> Surely this is plain wrong as well as being very inefficient? >>> >>> Inefficient how? When it succeeds or when it fails? >>> >> The typecheck typemap code is inefficient. It assumes any class with a >> __getitem__ has the potential to be converted into the appropriate STL >> container. It then goes off and tries to convert each element returned >> by __getitem__. Complete madness if you ask me. > > I don't see any madness in this, though I'm not wedded to it. Note that: > > 1. It *is* complete madness that the code does the check even when a > wrapped object of the right type is passed. This can easily be remedied > by doing the check for the right pointer type *first*, as pointed out in > that thread on performance. > Yup absolutely. > 2. When the check on a sequence type fails, it usually fails quickly. > Checking a Python string of length one million for suitability as a > vector<int> argument does not require iterating over one million > elements; the first one indicates its unsuitability. Fair enough. > Furthermore, in > the vast majority of cases there are only two possibilities when it does > fail (for Python strings or other non-proxy objects): > a. Some other signature of the overloaded function accepts it, and it is > converted to the appropriate C++ type by iterating over all its > elements. This makes the failed check insignificant. > b. No signature accepts it. The call was an error. Who cares about > efficiency (within reason) for illegal function calls? > Yup > 3. The checking and acceptance of SWIG-wrapped objects of the "wrong" > type is another issue (actually two issues: accepting them by conversion > when there's no other way to accept them, and accepting them this way > when another signature would accept them without conversion). However, > as you pointed out, you can eliminate this specifically for SWIG-wrapped > objects while allowing it for all other sequence types. Okay, so I've checked in a change it so that only non-SWIG objects go through the attempted sequence checking using this logic: 1. If input is a SWIG wrapped object, use the normal type checking only. So no conversion attempt is made eg vector<int> to vector<double> or list<int> to vector<int>. 2. Otherwise it is a non-SWIG wrapped object in which case check if a sequence and if so, attempt to convert each member into the appropriate c++ type. This way it will work more like the Ruby example Gonzalo mentioned, ie a vector<int> will not be shadowed by vector<double> whenever passing in a vector<int> wrapped object. William |