<html>
  <head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
  </head>
  <body text="#000000" bgcolor="#FFFFFF">
    <p>Brett,<br>
      <br>
      Thank you for bringing this up, but I think you <i>may</i> have
      misunderstood my position - though maybe you understood the thrust
      and wanted to clarify for people coming in halfway, which I
      applaud.</p>
    <p>I proposed this change <i>knowing</i> that it was a breaking
      change - it's why I brought it to the attention of datetime-SIG
      and now python-dev - and I believe that there are several factors
      that lead this to being a smaller compatibility problem than it
      seems.</p>
    <p>One such factor is the fact that <i>many</i> other features of
      `datetime`, including the implementation of `datetime.now()` are <i>already
        broken</i> in the current implementation for anyone who would be
      broken by this particular aspect of the semantic change. That is
      not saying that it's impossible that there is code out there that
      will break if this change goes through, it's just saying that the
      scope of the breakage is necessarily very limited.</p>
    <p>The reason I brought up the bug tracker is because between Python
      3.6 and Python 3.7, we in fact made a similar breaking change to
      the one I'm proposing here without thinking that anyone might be
      relying on the fact that they could do something like:<br>
      <br>
      class D(datetime.datetime):<br>
          def __new__(cls):<br>
              return cls.now()<br>
      <br>
      My point was that there have been no bug reports about the <i>existing
        change</i> that Guido was bringing up (his example itself does
      not work on Python 3.7!), which leads me to believe that few if
      any people are relying on the fact that it is possible to define a
      datetime subclass with a different default constructor.</p>
    <p>As I mentioned, it is likely possible to have a transition period
      where this would still work even if the subclassers have not
      created their own __add__ method.<br>
      <br>
      There is no way to create a similar deprecation/transition period
      for people relying on the fact that `type(datetime_obj +
      timedelta_obj) == datetime.datetime`, but I think this is honestly
      a sufficiently minor breakage that the good outweighs the harm. I
      will note that we have already made several such changes with
      respect to alternate constructors even though technically someone
      could have been relying on the fact that
      `MyDateTime(*args).replace(month=3)` returns a `datetime` object.</p>
    <p>This is not to say that we should lightly make the change (hence
      my canvassing for opinions), it is just that there is a good
      amount of evidence that, practically speaking, no one is relying
      on this, and in fact it is likely that people are writing code
      that assumes that adding `timedelta` to a datetime subclass
      returns the original subclass, either directly or indirectly - I
      think we're likely to fix more people than we break if we make
      this change.<br>
      <br>
      Best,<br>
      Paul<br>
    </p>
    <p><br>
    </p>
    <div class="moz-cite-prefix">On 1/6/19 3:24 PM, Brett Cannon wrote:<br>
    </div>
    <blockquote type="cite"
cite="mid:CAP1=2W7RnpW7HgpuDQPzZzfrMMzPXAGj8G91xQyRMU4qLV1btg@mail.gmail.com">
      <div dir="ltr">
        <div dir="ltr"><br>
        </div>
        <br>
        <div class="gmail_quote">
          <div dir="ltr">On Sun, 6 Jan 2019 at 11:00, Paul Ganssle <<a
              href="mailto:paul@ganssle.io" moz-do-not-send="true">paul@ganssle.io</a>>
            wrote:<br>
          </div>
          <blockquote class="gmail_quote">
            <div>
              <p>I did address this in the original post - the
                assumption that the subclass constructor will have the
                same arguments as the base constructor is baked into
                many alternate constructors of datetime. I acknowledge
                that this is a breaking change, but it is a small one -
                anyone creating such a subclass that <i>cannot</i>
                handled the class being created this way would be broken
                in myriad ways.<br>
                <br>
                We have also in recent years changed several alternate
                constructors (including `replace`) to retain the
                original subclass, which by your same standard would be
                a breaking change. I believe there have been no
                complaints. In fact, between Python 3.6 and 3.7, the
                very example you showed broke:<br>
                <br>
                Python 3.6.6:<br>
                <br>
                >>> class D(datetime.datetime):<br>
                ...     def __new__(cls):<br>
                ...         return cls.now()<br>
                ... <br>
                >>> D()<br>
                D(2019, 1, 6, 13, 49, 38, 842033)<br>
                <br>
                Python 3.7.2:<br>
                <br>
                >>> class D(datetime.datetime):<br>
                ...     def __new__(cls):<br>
                ...         return cls.now()<br>
                ... <br>
                >>> D()<br>
                Traceback (most recent call last):<br>
                  File "<stdin>", line 1, in <module><br>
                  File "<stdin>", line 3, in __new__<br>
                TypeError: __new__() takes 1 positional argument but 9
                were given</p>
              <p><br>
                We haven't seen any bug reports about this sort of
                thing; what we <i>have</i> been getting is bug reports
                that subclassing datetime doesn't retain the subclass in
                various ways (because people <i>are</i> using datetime
                subclasses).</p>
            </div>
          </blockquote>
          <div><br>
          </div>
          <div>To help set expectations, the current semantics are not a
            bug and so the proposal isn't fixing a bug but proposing a
            change in semantics.<br>
          </div>
          <div> </div>
          <blockquote class="gmail_quote">
            <div>
              <p> This is likely to cause very little in the way of
                problems, but it will improve convenience for people
                making datetime subclasses and almost certainly
                performance for people using them (e.g. pendulum and
                arrow, which now need to take a slow pure python route
                in many situations to work around this problem).</p>
              <p>If we're <i>really</i> concerned with this backward
                compatibility breaking, </p>
            </div>
          </blockquote>
          <div><br>
          </div>
          <div>We very much do care. Because this isn't a bug but a
            voluntary semantic change you're proposing to change we
            can't blindly break people who are relying on the current
            semantics. We need to have a justification for those people
            as to why we have decided to change the semantics now after
            all of these years as well as provide an upgrade path.</div>
          <div><br>
          </div>
          <div>-Brett<br>
          </div>
          <div> </div>
          <blockquote class="gmail_quote">
            <div>
              <p>we could do the equivalent of:<br>
                <tt><br>
                </tt><tt>try:</tt><tt><br>
                </tt><tt>    return new_behavior(...)</tt><tt><br>
                </tt><tt>except TypeError:</tt><tt><br>
                </tt><tt>    warnings.warn("The semantics of timedelta
                  addition have "</tt><tt><br>
                </tt><tt>                  "changed in a way that raises
                  an error in "<br>
                                    "this subclass. Please implement
                  __add__ "<br>
                                    "if you need the old behavior.",
                  DeprecationWarning)</tt> <br>
              </p>
            </div>
          </blockquote>
          <blockquote class="gmail_quote">
            <div>
              <p><tt> <br>
                </tt>Then after a suitable notice period drop the
                warning and turn it to a hard error.<br>
              </p>
              <p>Best,</p>
              <p>Paul<br>
              </p>
              <div class="gmail-m_8458662023297668833moz-cite-prefix">On
                1/6/19 1:43 PM, Guido van Rossum wrote:<br>
              </div>
              <blockquote type="cite">
                <div dir="ltr">
                  <div dir="ltr">
                    <div dir="ltr">
                      <div dir="ltr">
                        <div>I don't think datetime and builtins like
                          int necessarily need to be aligned. But I do
                          see a problem -- the __new__ and __init__
                          methods defined in the subclass (if any)
                          should allow for being called with the same
                          signature as the base datetime class.
                          Currently you can have a subclass of datetime
                          whose __new__ has no arguments (or, more
                          realistically, interprets its arguments
                          differently). Instances of such a class can
                          still be added to a timedelta. The proposal
                          would cause this to break (since such an
                          addition has to create a new instance, which
                          calls __new__ and __init__). Since this is a
                          backwards incompatibility, I don't see how it
                          can be done -- and I also don't see many use
                          cases, so I think it's not worth pursuing
                          further.<br>
                        </div>
                        <div><br>
                        </div>
                        <div>Note that the same problem already happens
                          with the .fromordinal() class method, though
                          it doesn't happen with .fromdatetime() or
                          .now():</div>
                        <div><br>
                        </div>
                        <div>>>> class D(datetime.datetime):<br>
                          ...   def __new__(cls): return cls.now()<br>
                          ... <br>
                          >>> D()<br>
                          D(2019, 1, 6, 10, 33, 37, 161606)<br>
                          >>> D.fromordinal(100)<br>
                          Traceback (most recent call last):<br>
                            File "<stdin>", line 1, in
                          <module><br>
                          TypeError: __new__() takes 1 positional
                          argument but 4 were given<br>
                          >>> D.fromtimestamp(123456789)<br>
                          D(1973, 11, 29, 13, 33, 9)<br>
                          >>> <br>
                        </div>
                      </div>
                    </div>
                  </div>
                </div>
                <br>
                <div class="gmail_quote">
                  <div dir="ltr">On Sun, Jan 6, 2019 at 9:05 AM Paul
                    Ganssle <<a href="mailto:paul@ganssle.io"
                      target="_blank" moz-do-not-send="true">paul@ganssle.io</a>>
                    wrote:<br>
                  </div>
                  <blockquote class="gmail_quote">
                    <div>
                      <p>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 <i>all</i> arithmetic
                        types <i>should</i> have some form of this
                        change.<br>
                      </p>
                      <p>That said, I would say that the biggest
                        difference between datetime and builtins (other
                        than the fact that datetime is <i>not</i> a
                        builtin, and as such doesn't necessarily need to
                        be categorized in this group), is that unlike
                        almost all other arithmetic types, <i>datetime</i>
                        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:<br>
                        <br>
                        >>> F(1.2) + 3.4<br>
                        <br>
                        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:<br>
                        <br>
                        datetime - datetime -> timedelta<br>
                        datetime ± timedelta -> datetime<br>
                        timedelta ± timedelta -> timedelta<br>
                        <br>
                        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.</p>
                      <p>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 <i>in this respect</i>. 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.<br>
                        <br>
                        Best,<br>
                        Paul<br>
                      </p>
                      <div
class="gmail-m_8458662023297668833gmail-m_-6009346472102158879moz-cite-prefix">On
                        1/5/19 3:55 AM, Alexander Belopolsky wrote:<br>
                      </div>
                      <blockquote type="cite">
                        <div dir="ltr">
                          <div dir="ltr">
                            <div dir="ltr">
                              <div dir="ltr"><br>
                              </div>
                              <br>
                              <div class="gmail_quote">
                                <div dir="ltr">On Wed, Jan 2, 2019 at
                                  10:18 PM Paul Ganssle <<a
                                    href="mailto:paul@ganssle.io"
                                    target="_blank"
                                    moz-do-not-send="true">paul@ganssle.io</a>>
                                  wrote:<br>
                                </div>
                                <blockquote class="gmail_quote">
                                  <div>
                                    <p>.. 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.</p>
                                  </div>
                                </blockquote>
                                <div>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:</div>
                                <div>
                                  <div><br>
                                  </div>
                                  <div>>>> class F(float):</div>
                                  <div>...     pass</div>
                                  <div>...</div>
                                </div>
                                <div>
                                  <div>>>>
                                    type(F.fromhex('AA'))</div>
                                  <div><class '__main__.F'></div>
                                  <div>>>> type(F(1) + F(2))</div>
                                  <div><class 'float'></div>
                                </div>
                                <div><br>
                                </div>
                                <blockquote class="gmail_quote">
                                  <div>
                                    <p> 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).</p>
                                  </div>
                                </blockquote>
                                <div><br>
                                </div>
                                <div>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.  </div>
                              </div>
                            </div>
                          </div>
                        </div>
                      </blockquote>
                    </div>
                    _______________________________________________<br>
                    Python-Dev mailing list<br>
                    <a href="mailto:Python-Dev@python.org"
                      target="_blank" moz-do-not-send="true">Python-Dev@python.org</a><br>
                    <a
                      href="https://mail.python.org/mailman/listinfo/python-dev"
                      rel="noreferrer" target="_blank"
                      moz-do-not-send="true">https://mail.python.org/mailman/listinfo/python-dev</a><br>
                    Unsubscribe: <a
href="https://mail.python.org/mailman/options/python-dev/guido%40python.org"
                      rel="noreferrer" target="_blank"
                      moz-do-not-send="true">https://mail.python.org/mailman/options/python-dev/guido%40python.org</a><br>
                  </blockquote>
                </div>
                <br>
                <br>
                -- <br>
                <div dir="ltr"
                  class="gmail-m_8458662023297668833gmail_signature">--Guido
                  van Rossum (<a href="http://python.org/~guido"
                    target="_blank" moz-do-not-send="true">python.org/~guido</a>)</div>
              </blockquote>
            </div>
            _______________________________________________<br>
            Python-Dev mailing list<br>
            <a href="mailto:Python-Dev@python.org" target="_blank"
              moz-do-not-send="true">Python-Dev@python.org</a><br>
            <a
              href="https://mail.python.org/mailman/listinfo/python-dev"
              rel="noreferrer" target="_blank" moz-do-not-send="true">https://mail.python.org/mailman/listinfo/python-dev</a><br>
            Unsubscribe: <a
href="https://mail.python.org/mailman/options/python-dev/brett%40python.org"
              rel="noreferrer" target="_blank" moz-do-not-send="true">https://mail.python.org/mailman/options/python-dev/brett%40python.org</a><br>
          </blockquote>
        </div>
      </div>
    </blockquote>
  </body>
</html>