[Python-Dev] Return type of datetime subclasses added to timedelta

Paul Ganssle paul at ganssle.io
Sun Jan 6 11:02:43 EST 2019

I can think of many reasons why datetime is different from builtins,
though to be honest I'm not sure that consistency for its own sake is
really a strong argument for keeping a counter-intuitive behavior - and
to be honest I'm open to the idea that /all/ arithmetic types /should/
have some form of this change.

That said, I would say that the biggest difference between datetime and
builtins (other than the fact that datetime is /not/ a builtin, and as
such doesn't necessarily need to be categorized in this group), is that
unlike almost all other arithmetic types, /datetime/ has a special,
dedicated type for describing differences in datetimes. Using your
example of a float subclass, consider that without the behavior of
"addition of floats returns floats", it would be hard to predict what
would happen in this situation:

>>> F(1.2) + 3.4

Would that always return a float, even though F(1.2) + F(3.4) returns an
F? Would that return an F because F is the left-hand operand? Would it
return a float because float is the right-hand operand? Would you walk
the MROs and find the lowest type in common between the operands and
return that? It's not entirely clear which subtype predominates. With
datetime, you have:

datetime - datetime -> timedelta
datetime ± timedelta -> datetime
timedelta ± timedelta -> timedelta

There's no operation between two datetime objects that would return a
datetime object, so it's always clear: operations between datetime
subclasses return timedelta, operations between a datetime object and a
timedelta return the subclass of the datetime that it was added to or
subtracted from.

Of course, the real way to resolve whether datetime should be different
from int/float/string/etc is to look at why this choice was actually
made for those types in the first place, and decide whether datetime is
like them /in this respect/. The heterogeneous operations problem may be
a reasonable justification for leaving the other builtins alone but
changing datetime, but if someone knows of other fundamental reasons why
the decision to have arithmetic operations always create the base class
was chosen, please let me know.


On 1/5/19 3:55 AM, Alexander Belopolsky wrote:
> On Wed, Jan 2, 2019 at 10:18 PM Paul Ganssle <paul at ganssle.io
> <mailto:paul at ganssle.io>> wrote:
>     .. the original objection was that this implementation assumes
>     that the datetime subclass has a constructor with the same (or a
>     sufficiently similar) signature as datetime.
> While this was used as a possible rationale for the way standard types
> behave, the main objection to changing datetime classes is that it
> will make them behave differently from builtins.  For example:
> >>> class F(float):
> ...     pass
> ...
> >>> type(F.fromhex('AA'))
> <class '__main__.F'>
> >>> type(F(1) + F(2))
> <class 'float'>
>     This may be a legitimate gripe, but unfortunately that ship has
>     sailed long ago. All of datetime's alternate constructors make
>     this assumption. Any subclass that does not meet this requirement
>     must have worked around it long ago (or they don't care about
>     alternate constructors).
> This is right, but the same argument is equally applicable to int,
> float, etc. subclasses.  If you want to limit your change to datetime
> types you should explain what makes these types special.  
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-dev/attachments/20190106/8f7a75a7/attachment.html>
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: OpenPGP digital signature
URL: <http://mail.python.org/pipermail/python-dev/attachments/20190106/8f7a75a7/attachment.sig>

More information about the Python-Dev mailing list