
Can anyone explain to me why we need both trunc() and int()? We used to be very resistant to adding new built-ins and magic method protocols. In days not long past, this would have encountered fierce opposition. ISTM that numbers.py has taken on a life of its own and is causing non-essential offspring to sprout-up everywhere. Also, it seems that ABC is starting to evolve from an optional tool into something embedded in the language in a way that you can't escape it. I would prefer that it not be on the list of concepts that a beginner *must* know in order to be functional in the language. There are a handful of needs met by the numeric tower but they only warrant minimal changes to the language. Raymond P.S. The docstring for trunc() makes it sound like an imprecisely specified version of round(). ---- trunc() looks like int() but it isn't --------------------------- trunc(Real) -> Integral returns the integral closest to x between 0 and x.

On Jan 24, 2008 10:36 AM, Raymond Hettinger <python@rcn.com> wrote:
Can anyone explain to me why we need both trunc() and int()?
trunc() has well-defined semantics -- it takes a Real instance and converts it to an Integer instance using round-towards-zero semantics. int() has undefined semantics -- it takes any object and converts it to an int (a concrete type!) using whatever rules it likes -- the definition of __int__ is up to whatever the source type likes to do. For float this has been defined the same as trunc() above, but for other types, who knows! int() of a string does something completely different. Perhaps worse is that sometimes int() is lossy (e.g. with a float input) and sometimes it is not (e.g. with a string input, or with a non-standard representation of integers). There are still some places where a float is accepted incorrectly (silently truncating) due to the use of the __int__ slot. If trunc() had been part of the language from the beginning we wouldn't have needed to introduce __index__. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

trunc() has well-defined semantics -- it takes a Real instance and converts it to an Integer instance using round-towards-zero semantics.
No. trunc calls __trunc__, which does whatever it pleases to do.
But why is that a reason to keep trunc()? If you only ever want to convert floats to ints, you can use either one, with no difference. int() does *not* have undefined semantics, for floats, it converts it to an integer using round-towards-zero semantics. Regards, Martin

On Jan 24, 2008 11:36 AM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
However, PEP 3141 specifies what it should do for Numbers.
Yes (although it wasn't always specified this way). But I don't like that, because of the ambiguity of int(x). -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Jan 24, 2008 12:46 PM, Guido van Rossum <guido@python.org> wrote:
What are the use-cases for when trunc() vs int() should be used, and for when a class should define __trunc__ vs __int__? This might help clear up whether both deserve to be a built-in, as well provide a starting point for 3.0 best practices. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises LLC

On Jan 24, 2008 1:09 PM, Daniel Stutzbach <daniel@stutzbachenterprises.com> wrote:
If you intend to convert a real number (usually float, since Decimal has decided not to support it) to an Integral (usually int), use whichever of trunc(), round(), math.floor(), or math.ceil() you intend. In 2.6, that list only includes trunc(). If you absolutely need an int (the concrete, not duck type) from an Integral or you want to parse a string, use int(). Real numbers should define __trunc__. Integrals and, perhaps, some string-like types (maybe an MD5 class?) should define __int__. At least, that's my suggestion. -- Namasté, Jeffrey Yasskin

So, the problem is basically this: Since int(o) must return an int, you're precluded from defining a new Real class with an __int__() method that returns an instance of some new Integral class that isn't an int. And the proposed solution is: Introduce trunc(o) which calls o.__trunc__() which can return any Integral type. And, client code must use trunc() instead of int(); otherwise, the two new numeric types won't be exercised. Is that basically what trunc() is all about -- a variant of int() that can return something other than an int type -- something that behaves just like the new math.floor() for positive numbers and math.ceil() for negative numbers? If so, I think we would be *much* better-off leaving trunc() out entirely and seeing if any use cases arise that aren't handled by math.floor() and math.ceil() with their precise semantics, unambigous naming, and ability to handle generic Reals and Integrals. The existence of trunc() clashes so severely with existence of int(), that we need to be damned sure that there are real-world, worthwhile problems that are not readily solved with floor() and ceil() for rounding Reals into Integrals or with int() for making ints from the non-fractional portion of a float. Raymond

On Jan 25, 2008 11:21 PM, Raymond Hettinger <python@rcn.com> wrote:
... int() for making ints from the non-fractional portion of a float.
This interpretation implies that complex should provide __float__() to return the non-imaginary portion of a complex number. Is that what you intend? -- Namasté, Jeffrey Yasskin

On Jan 26, 2008 2:46 PM, Raymond Hettinger <python@rcn.com> wrote:
To elaborate the point I was trying to make: If float() does not mean "the float part of" and should not take a complex argument (which I completely agree with), then int() does not mean "the int part of" and should not take a float argument. Even assuming that's correct, I'm not certain that it's worth breaking (well, deprecating) backwards compatibility to achieve a more consistent set of functions in this case. I think it is, but I'm happy to leave that point up to the rest of the list (which does seem to be leaning against it). -- Namasté, Jeffrey Yasskin

"Jeffrey Yasskin" <jyasskin@gmail.com> wrote in message news:5d44f72f0801261600l4ea2d006vd58fa5999ba73197@mail.gmail.com... || To elaborate the point I was trying to make: If float() does not mean | "the float part of" The 'float part' of a complex number is meaningless since both components of a complex are floats (in practice, or reals in theory). The same is true in polar representation. | and should not take a complex argument (which I | completely agree with), then int() does not mean "the int part of" and | should not take a float argument. The 'integer (int) part' of a float/rational/real is established thru decades of usage. Your consequent is false and in no way follows from your antecendent. tjr

To me, the concept of the "integer part of a float" isn't all that well defined. It's really a property of a particular representation rather than the number itself. You think of it as a string of digits and chop off the part after the point, then turn what's left back into a number. If negative floats were represented in two's complement, for example, then chopping off the digits after the point would give a result more like floor than trunc. -- Greg

Hi Raymond, On Thu, Jan 24, 2008 at 01:36:14PM -0500, Raymond Hettinger wrote:
I can't resist to mention some private discussions I've had at the time, with people that could see this coming. Maybe this might be used as an argument against adding optional type annotations...? Ok, I'm not optimistic about it. Sorry, I don't mean to start yet another endless thread, and will shut up again after this note. I'm no longer a regular python-dev contributor anyway; the fact is that I quite like the language as it is, and I'm a bit concerned about its evolution - in my humble opinion it seems to become each release a bit less accessible to beginners. A bientot, Armin

On Jan 24, 2008 10:36 AM, Raymond Hettinger <python@rcn.com> wrote:
Can anyone explain to me why we need both trunc() and int()?
trunc() has well-defined semantics -- it takes a Real instance and converts it to an Integer instance using round-towards-zero semantics. int() has undefined semantics -- it takes any object and converts it to an int (a concrete type!) using whatever rules it likes -- the definition of __int__ is up to whatever the source type likes to do. For float this has been defined the same as trunc() above, but for other types, who knows! int() of a string does something completely different. Perhaps worse is that sometimes int() is lossy (e.g. with a float input) and sometimes it is not (e.g. with a string input, or with a non-standard representation of integers). There are still some places where a float is accepted incorrectly (silently truncating) due to the use of the __int__ slot. If trunc() had been part of the language from the beginning we wouldn't have needed to introduce __index__. -- --Guido van Rossum (home page: http://www.python.org/~guido/)

trunc() has well-defined semantics -- it takes a Real instance and converts it to an Integer instance using round-towards-zero semantics.
No. trunc calls __trunc__, which does whatever it pleases to do.
But why is that a reason to keep trunc()? If you only ever want to convert floats to ints, you can use either one, with no difference. int() does *not* have undefined semantics, for floats, it converts it to an integer using round-towards-zero semantics. Regards, Martin

On Jan 24, 2008 11:36 AM, "Martin v. Löwis" <martin@v.loewis.de> wrote:
However, PEP 3141 specifies what it should do for Numbers.
Yes (although it wasn't always specified this way). But I don't like that, because of the ambiguity of int(x). -- --Guido van Rossum (home page: http://www.python.org/~guido/)

On Jan 24, 2008 12:46 PM, Guido van Rossum <guido@python.org> wrote:
What are the use-cases for when trunc() vs int() should be used, and for when a class should define __trunc__ vs __int__? This might help clear up whether both deserve to be a built-in, as well provide a starting point for 3.0 best practices. -- Daniel Stutzbach, Ph.D. President, Stutzbach Enterprises LLC

On Jan 24, 2008 1:09 PM, Daniel Stutzbach <daniel@stutzbachenterprises.com> wrote:
If you intend to convert a real number (usually float, since Decimal has decided not to support it) to an Integral (usually int), use whichever of trunc(), round(), math.floor(), or math.ceil() you intend. In 2.6, that list only includes trunc(). If you absolutely need an int (the concrete, not duck type) from an Integral or you want to parse a string, use int(). Real numbers should define __trunc__. Integrals and, perhaps, some string-like types (maybe an MD5 class?) should define __int__. At least, that's my suggestion. -- Namasté, Jeffrey Yasskin

So, the problem is basically this: Since int(o) must return an int, you're precluded from defining a new Real class with an __int__() method that returns an instance of some new Integral class that isn't an int. And the proposed solution is: Introduce trunc(o) which calls o.__trunc__() which can return any Integral type. And, client code must use trunc() instead of int(); otherwise, the two new numeric types won't be exercised. Is that basically what trunc() is all about -- a variant of int() that can return something other than an int type -- something that behaves just like the new math.floor() for positive numbers and math.ceil() for negative numbers? If so, I think we would be *much* better-off leaving trunc() out entirely and seeing if any use cases arise that aren't handled by math.floor() and math.ceil() with their precise semantics, unambigous naming, and ability to handle generic Reals and Integrals. The existence of trunc() clashes so severely with existence of int(), that we need to be damned sure that there are real-world, worthwhile problems that are not readily solved with floor() and ceil() for rounding Reals into Integrals or with int() for making ints from the non-fractional portion of a float. Raymond

On Jan 25, 2008 11:21 PM, Raymond Hettinger <python@rcn.com> wrote:
... int() for making ints from the non-fractional portion of a float.
This interpretation implies that complex should provide __float__() to return the non-imaginary portion of a complex number. Is that what you intend? -- Namasté, Jeffrey Yasskin

On Jan 26, 2008 2:46 PM, Raymond Hettinger <python@rcn.com> wrote:
To elaborate the point I was trying to make: If float() does not mean "the float part of" and should not take a complex argument (which I completely agree with), then int() does not mean "the int part of" and should not take a float argument. Even assuming that's correct, I'm not certain that it's worth breaking (well, deprecating) backwards compatibility to achieve a more consistent set of functions in this case. I think it is, but I'm happy to leave that point up to the rest of the list (which does seem to be leaning against it). -- Namasté, Jeffrey Yasskin

"Jeffrey Yasskin" <jyasskin@gmail.com> wrote in message news:5d44f72f0801261600l4ea2d006vd58fa5999ba73197@mail.gmail.com... || To elaborate the point I was trying to make: If float() does not mean | "the float part of" The 'float part' of a complex number is meaningless since both components of a complex are floats (in practice, or reals in theory). The same is true in polar representation. | and should not take a complex argument (which I | completely agree with), then int() does not mean "the int part of" and | should not take a float argument. The 'integer (int) part' of a float/rational/real is established thru decades of usage. Your consequent is false and in no way follows from your antecendent. tjr

To me, the concept of the "integer part of a float" isn't all that well defined. It's really a property of a particular representation rather than the number itself. You think of it as a string of digits and chop off the part after the point, then turn what's left back into a number. If negative floats were represented in two's complement, for example, then chopping off the digits after the point would give a result more like floor than trunc. -- Greg

Hi Raymond, On Thu, Jan 24, 2008 at 01:36:14PM -0500, Raymond Hettinger wrote:
I can't resist to mention some private discussions I've had at the time, with people that could see this coming. Maybe this might be used as an argument against adding optional type annotations...? Ok, I'm not optimistic about it. Sorry, I don't mean to start yet another endless thread, and will shut up again after this note. I'm no longer a regular python-dev contributor anyway; the fact is that I quite like the language as it is, and I'm a bit concerned about its evolution - in my humble opinion it seems to become each release a bit less accessible to beginners. A bientot, Armin
participants (9)
-
"Martin v. Löwis"
-
Armin Rigo
-
Christian Heimes
-
Daniel Stutzbach
-
Greg Ewing
-
Guido van Rossum
-
Jeffrey Yasskin
-
Raymond Hettinger
-
Terry Reedy