[Development] Deprecation/removal model going into Qt 6

Manuel Bergler berglerma at gmail.com
Mon Jun 3 03:32:26 CEST 2019

Am Mo., 3. Juni 2019 um 02:21 Uhr schrieb Konstantin Shegunov
<kshegunov at gmail.com>:
> On Mon, Jun 3, 2019 at 2:10 AM Manuel Bergler <berglerma at gmail.com> wrote:
>> Why should software be different?
> It shouldn't, as already pointed out. That's why well behaved libraries try to keep compatibility in some reasonable margins.
> To throw one more stone here - are you willing to backport patches from latter minor versions to former ones? When the API and ABI breaks often that isn't very trivial, is it?

In my experience it isn't changes in the API but changes in the
implementation that make backporting hard. If, say, an API was changed
from taking a boolean parameter to an enum than backporting a patch
doesn't cause many problems, if instead the API has stayed the same
but the implementation now uses 3 helper classes that weren't there
before than it becomes tricky. So I'd say API and ABI stability don't
have much impact on backporting patches.

> On Mon, Jun 3, 2019 at 2:47 AM Manuel Bergler <berglerma at gmail.com> wrote:
>> a) Qt can never remove superseded APIs and classes (which is what
>> you suggested previously) and will eventually collapse under its own
>> weight, or
> It can under the current model where API and ABI breaking may happen between major versions, which I find rather reasonable.

Which is once every 7 (?) years, and even then we can't agree on what
to get rid of because getting rid of all problematic APIs would cause
so many breaking changes that no one is willing to port all of that
and you'd definitely end up with something similar to the Python 2/3

>> b) Distributors have to deal with the fact that some software
>> doesn't port and have to ship every version of qt side-by-side, or
> Like they do with boost? Which they don't, obviously.
> It simply ain't going to happen they're not an infinite well of computer and human time.
> Also are you suggesting that all applications sync up theirs to your release cycle? Or are the distros to do that?

I think I wasn't clear enough with how I imagine breaking API changes
to work. I'm not suggesting to just change the API and/or ABI whenever
just for the sake of it. There needs to be a properly documented
migration path, possibly with a decision tree if the replacement isn't
straight forward. Once internally we agree on a migration path, first
implement the replacement API and in the same version that ships that
API mark the old one deprecated. In the deprecation message should
also be a link to the document explaining how to migrate. And in the
following minor release remove the previously deprecated API. For
example, assuming QTimer didn't have the API taking std::chrono
parameter already, one could introduce that API in Qt 6.0 and
simultaneously mark the one taking plain integers as deprecated. In Qt
6.1 I'd remove the old API.

That way, assuming everyone has ported to minor version `n` properly,
distributions can roll out minor version `n + 1`. Of course, as
someone else already suggested we could also have deprecations and
consequently removal only in LTS versions, I don't really care. What I
do care about is the ability to evolve the APIs in such a way that
they become easier to use correctly, easier to teach and harder to
accidentally misuse, without having to maintain APIs that shouldn't be
used anyway.

> If porting the application between minor versions takes more time than the time to introduce a breaking change, then you're never going to port anything as this is all you're going to do ultimately.

That's the entire point of spreading the breaking changes out; it
should never take more than a few days to port to the new version.

>> c) The software that doesn't port has to deal with the fact that it
>> will be dropped by distributions. But any software with sufficiently
>> many users to warrant packaging by the distributors should be able to
>> find a maintainer that at least can keep it compiling.
> Keeping something compiling is different from keeping something working; not to mention that API breaks are non-trivial to port.
Yeah, I should have written "working" instead of "compiling". However,
I find that API breaks are typically easy to port as long as there is
a documented migration part; most changes can be done by simple
search-and-replace. As I already mentioned before, the silent behavior
changes are what makes porting slow.

> Also this is not a distributions' problem exclusively. Clients of Qt expect, and rightfully so, binary compatibility which was promised.
It is only promised for Qt5, which is why we're having the discussion
whether that promise should also hold for Qt 6.

> It wouldn't be surprising to me to find an ebb of usage if we start breaking the ABI every 6 months just because we decided we can. I don't even want to venture into the rabbit hole that is 6-month lifetime of APIs.

Just to reiterate, I'm not suggesting to just break ABI because we
can, I just want to allow it for the cases where everyone agrees that
it is beneficial. Take QWidget for example: Many events have their own
specialized event handler (e.g. `QWidget::mouseClickEvent`) one can
override in inheriting classes. But due to ABI compatibility
guarantees, if a new event type is added, we cannot add a
corresponding specialized event handler in Qt5, which is why sometimes
events need to be handled in the general `event` function. If we could
agree that breaking the ABI is allowed even in minor version, then the
generic `event` function wouldn't need to be part of the API but
merely an implementation detail, and all event handling could be done
via specialized member functions - even if new event types are added
down the road.

ABI breaking changes should still be rare, but not completely ruled
out. And in the cases where we do make ABI breaking changes, they
shouldn't cause silent runtime crashes but already lead to linker
errors -> inline namespaces.


More information about the Development mailing list