[Python-Dev] Passing floats to "i" parser marker

M.-A. Lemburg mal@lemburg.com
Wed, 05 Feb 2003 17:36:38 +0100


Guido van Rossum wrote:
>>>Since all the type knows is that it's __int__ method is called, not
>>>that this is in the context of getargs.c, how could it protest in this
>>>case without protesting about all calls to int()?
>>
>>But that's the point: "i" should work just like int() does
>>w/r to the __int__ slot and it does, so nothing is broken
>>which would need fixing.
> 
> Well, that's where we disagree.  I think "i" is broken and needs
> fixing.
> 
> The history:
> 
> Long ago, "i" and friends only accepted honest-to-god ints; if you had
> something else that implemented __int__, you had to call int() on it
> before passing it along.  list.insert() only accepted ints for the
> index, and all was good.
> 
> Then someone suggested that it wasn't fair that built-in ints had
> special status when passed to a function implemented in C, and that
> anything that supported __int__ should be allowed.  The use case
> (though we didn't have that word then yet) was some user-defined type
> that represented an int with additional behavior (it was before you
> could subclass int).
> 
> It wasn't until years after the idea was implemented that I realized
> that floats also have an __int__ method and that you could write not
> only "list.insert(3.0, xxx)", which was arguably acceptable, but also
> "list.insert(3.14, xxx)", which was definitely not.
> 
> So the warning for "i" is an attempt at a fix for this that has the
> largest bang for the buck (as opposed to introducing a second method
> for lossy conversions to int, which would be much more work and cause
> much more broken code).
> 
>>IMHO, the right way to fix what you think is broken is by introducing
>>a new parser marker with your new semantics. Then use that parser
>>marker whereever it is found meaningful.
> 
> Tell that to the people who have to maintain thousands of PyArg_*
> calls.

I'm one of them :-)

> I think that a parser marker meaning "accept a float but truncate it
> to int" would not find much use.

I was trying to suggest a parser marker for "accept whole
numbers only", ie. floats without fraction, integers, subclasses
of integers and other classes implementating __int__.

 >>...
>>No, this is one spot where the new parser marker would fit
>>well. Still, even in this case I think that passing
>>floats to "i" is perfectly OK, namely in all those cases
>>where no loss of data occurs, e.g. passing 13.0 to "i"
>>should be accepted as 13.
> 
> Smarter people than you and me can disagree about that.  Personally, I
> think that accepting floats with int values here is asking for
> trouble: a calculation that returns a perfect int on one machine may
> not do so on another, and hence a subtle portability problem is born.

True. I was thinking of cases where some external lib
returns floats even for integers (e.g. database interface
which return DECIMAL columns with scale 0 as floats --
Zope converts these to integers; even though these can
overflow). Now, you'll never see a float coming out of
that interface with a non-0 fraction. With the change you'll
also won't be able to pass the value as parameter to many
thousand Python APIs anymore.

To work around this, the interface would have to be changed
to apply a magic similar to the one Zope uses. But then
you have a different problem: a change in data type based
on a database type parameter.

>>>>Which makes me think: int() started
>>>>to return longs a few months ago -- we don't even have
>>>>a cast which would raise an OverlfowError in case
>>>>the conversion to int is not possible.
>>>
>>>Why would you need one (except in C code, where "i" is such a cast)?
>>
>>For exactly this case -- to make sure that "i" doesn't
>>overflow when receiving the return value from int().
> 
> This makes no sense.  "i" gives a perfectly valid error message when
> passed a value that's too long to fit in a C int -- in fact, the error
> message is exactly the same as you used to get from int(x) if x were a
> long larger than sys.maxint.

That's what I meant:

Python 2.3a1:
 >>> int(123478987123L)
123478987123L

Now, if I want to make sure that I can pass the value to
"i" I'll have to add another check which makes sure that
the int() return value is indeed a standard integer.

>>>YAGNI.
>>
>>I wasn't proposing anything in the above paragraph...
>>what does YAGNI apply to here ?
> 
> I sohuld have invented a new acronym.  What I meant was YAWTM (You Are
> Worrying Too Much).

Perhaps,
-- 
Marc-Andre Lemburg
CEO eGenix.com Software GmbH
_______________________________________________________________________
eGenix.com -- Makers of the Python mx Extensions: mxDateTime,mxODBC,...
Python Consulting:                               http://www.egenix.com/
Python Software:                    http://www.egenix.com/files/python/