Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deprecate delegation of int to __trunc__ #89140

Closed
mdickinson opened this issue Aug 22, 2021 · 12 comments
Closed

Deprecate delegation of int to __trunc__ #89140

mdickinson opened this issue Aug 22, 2021 · 12 comments
Labels
3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)

Comments

@mdickinson
Copy link
Member

BPO 44977
Nosy @rhettinger, @mdickinson, @serhiy-storchaka, @ZackerySpytz
PRs
  • bpo-44977: Deprecate delegation of int to __trunc__ #31031
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = None
    closed_at = <Date 2022-02-03.09:44:44.771>
    created_at = <Date 2021-08-22.09:17:57.051>
    labels = ['interpreter-core', '3.11']
    title = 'Deprecate delegation of int to __trunc__'
    updated_at = <Date 2022-02-03.09:44:44.770>
    user = 'https://github.com/mdickinson'

    bugs.python.org fields:

    activity = <Date 2022-02-03.09:44:44.770>
    actor = 'serhiy.storchaka'
    assignee = 'none'
    closed = True
    closed_date = <Date 2022-02-03.09:44:44.771>
    closer = 'serhiy.storchaka'
    components = ['Interpreter Core']
    creation = <Date 2021-08-22.09:17:57.051>
    creator = 'mark.dickinson'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 44977
    keywords = ['patch']
    message_count = 12.0
    messages = ['400063', '400064', '400073', '400074', '400076', '400078', '400079', '400080', '400082', '412190', '412431', '412432']
    nosy_count = 4.0
    nosy_names = ['rhettinger', 'mark.dickinson', 'serhiy.storchaka', 'ZackerySpytz']
    pr_nums = ['31031']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue44977'
    versions = ['Python 3.11']

    @mdickinson
    Copy link
    Member Author

    The int constructor, when applied to a general Python object obj, first looks for an int method, then for an index method, and then finally for a trunc method.

    The delegation to __trunc__ used to be useful: it meant that users could write a custom class SomeNumber with the property that:

    • SomeNumber instances supported 'int' calls, returning a truncated value, but
    • SomeNumber instances weren't usable in indexing, chr() calls, and all the various other calls that implicitly invoked __int__.
    class SomeNumber:
        def __trunc__(self):
           <return truncated value for self>

    However, with Python >= 3.10, we no longer use __int__ implicitly for argument conversion in internal code. So the second point above is no longer a concern, and SomeNumber can now simply be written as

    class SomeNumber:
        def __int__(self):
           <return truncated value for self>

    This decouples int from __trunc__ and leaves __trunc__ as simply the support for the math.trunc function.

    @mdickinson
    Copy link
    Member Author

    This decouples int from __trunc__ and leaves __trunc__ as simply the support for the math.trunc function.

    Argh; copy and paste fail - I left out the crucial line.

    I propose deprecating the delegation of int to __trunc__: calls to int(a) where type(a) implements __trunc__ but not __int__ or __index__ would raise a DeprecationWarning, and at some point in the future int(a) would become a TypeError.

    @serhiy-storchaka
    Copy link
    Member

    Completely agree.

    @rhettinger
    Copy link
    Contributor

    Afterwards, do __trunc__ and math.trunc() still need to exist?

    They were mostly unused. Now they would also be unnecessary. Just having them around would be a point of confusion.

    @mdickinson
    Copy link
    Member Author

    A GitHub code search shows a substantial number of uses of math.trunc out in the wild:

    https://github.com/search?q=math.trunc+extension%3Apy&type=Code

    So unfortunately, getting rid of math.trunc and __trunc__ looks a bit too much as though it would cause gratuitous breakage.

    @rhettinger
    Copy link
    Contributor

    Possibly, we could have math.trunc() call __int__, letting us deprecate __trunc__.

    That would let users avoid gratuitous aliasing such as that in _pydecimal.py:

       __trunc__ = __int__

    @serhiy-storchaka
    Copy link
    Member

    I do not think that math.trunc() for UUID or IP4Address makes sense.

    @mdickinson
    Copy link
    Member Author

    I think the needs are sufficiently different that __trunc__ still has value as its own thing, and it's a natural counterpart to __floor__ and __ceil__ (out of all the directed rounding modes, rounding towards zero probably turns up more often than rounding towards +inf or -inf).

    __int__ has the disadvantage that it must return an int, so it's not useful for other Python-based numeric systems with their own rational number / integer pairing. For example, with gmpy2, truncating an mpq instance returns an mpz instance, which is what I'd expect and want - if I'm working with huge values then it would be annoying for math.trunc to do the inefficient thing and return a plain int.

    >>> from gmpy2 import mpq
    >>> math.trunc(mpq(22, 7))
    mpz(3)

    SymPy behaves similarly:

    >>> from sympy import Rational
    >>> type(math.trunc(Rational(22, 7)))
    <class 'sympy.core.numbers.Integer'>

    On the other side, there are conversions to integer that it doesn't make sense to think of as truncation. It would be odd for a UUID to be a valid input to math.trunc, for example:

    >>> int(uuid.uuid4())
    43341414945793370480422623795805641537

    @rhettinger
    Copy link
    Contributor

    I retract the suggestion to deprecate __trunc__.

    @serhiy-storchaka serhiy-storchaka added 3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Oct 15, 2021
    @serhiy-storchaka serhiy-storchaka changed the title Deprecate delegation of int to __trunc__? Deprecate delegation of int to __trunc__ Oct 15, 2021
    @serhiy-storchaka serhiy-storchaka added 3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs) labels Oct 15, 2021
    @serhiy-storchaka serhiy-storchaka changed the title Deprecate delegation of int to __trunc__? Deprecate delegation of int to __trunc__ Oct 15, 2021
    @ZackerySpytz
    Copy link
    Mannequin

    ZackerySpytz mannequin commented Jan 31, 2022

    I have created a patch for this issue. Please consider having a look.

    @serhiy-storchaka
    Copy link
    Member

    New changeset b4bd1e1 by Zackery Spytz in branch 'main':
    bpo-44977: Deprecate delegation of int to __trunc__ (GH-31031)
    b4bd1e1

    @serhiy-storchaka
    Copy link
    Member

    Thanks Zackery.

    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 only security fixes interpreter-core (Objects, Python, Grammar, and Parser dirs)
    Projects
    None yet
    Development

    No branches or pull requests

    3 participants