John Machin wrote: > Peter Wang wrote: > > Bruno Desthuilliers wrote: > > > <my humble opinion> > > > Python is dynamic, and fighting against the language is IMHO a really > > > bad idea. The only places where theres a real need for this kind of > > > stuff are when dealing with the "outside world" (IOW : inputs and > > > outputs). And then packages like formencode can do much more than mere > > > type-checking > > > </my humble opinion> > > > > I don't think proper use of type checking is "fighting against the > > language". The goal of any language is to enable programmers to > > express their intent in a form that executes correctly. > > > > Python is extremely expressive but there is a trade-off with > > correctness - you can easily say something that you don't mean. Unit > > testing is sometimes sufficient, but it can never span the infinite > > space of potential errors. Type-checking method signatures guarantees > > a certain amount of low-level correctness, and most type-checking > > mechanisms also serve as documentation aids. > > > > I think that with a sufficiently sophisticated type checking syntax, > > one can get the best of both worlds. If the type checker understood > > interfaces (like PyProtocols) and its syntax had the flexibility to > > indicate sets of allowed arguments and aggregates of allowed > > types/interfaces, it would cover the majority of cases without limiting > > expressive power. > > > > I understand that we're all adults, but it's still nice to have the > > computer tell us when we're being childish. :) > > Your comments on the following cut-down and disguised version of a > *real-world* example would be appreciated: > > @accepts(object, (int, float)) > def tally(self, anobj): > self.total += anobj > > I assure you that the comments of a caller whose code did this: > fubar.tally(someobj) > and got this: > AssertionError: arg 12345678901L does not match (<type 'int'>, > <type 'float'>) > are definitely *not* repeatable in front of the children.
I guess this is not the 'accepts' decorator of the typecheck module; with that you'd rather write it as @accepts(Self(), Number) and prevent this error (http://oakwinter.com/code/typecheck/tutorial/methods.html). I have also a very recent real-world example to share, from the other side of the fence this time. It's even worse because it's an error that passes silently. Cut-down version follows: @cherrypy.expose def retrieve(self, **kwds): queries = kwds['q'] rows = self._selectRows(*queries) # more stuff 'q' here is a multiselect field that is binded to a list of selected strings. Or so I thought, until someone noticed bizarre results in some cases. Turns out that if you select a single item from the select box, 'q' is binded to a string instead of a list of length 1, so instead of retrieving 'apple', she got back the results for 'a', 'p', 'p', 'l','e'. Bottom line, type checking is a tricky business. In some sense it's similar to the recall/precision tradeoff in information retrieval. With stricter type checking, you can increase the precision but may hurt the recall, i.e. valid code is rejected, as in your example. And vice versa, loosing up the type checks increases the recall but may hurt the precision, as in my example. George -- http://mail.python.org/mailman/listinfo/python-list