[Development] Calendar classes: API review request

Edward Welbourne edward.welbourne at qt.io
Mon Aug 13 20:03:46 CEST 2018




On Dienstag, 31. Juli 2018 14:25:21 CEST Edward Welbourne wrote:
>>> My primary concern with this API is that it promotes an unclear
>>> ownership model.

>> hmm ... this is partly a symptom of most QAbstractCalendar instances
>> being dataless.  Each calendar has different code to implement its
>> behaviour.  Or, to put it another way, the vtable is the data.
>>
>> Admittedly, I can imagine uses for derived classes that do have data
>> (e.g. for historians of Europe, taking into account the use of Julian
>> for part of history, Gregorian for other parts, with diverse dates for
>> the transition - and some foibles in between), so we should make it
>> possible for them to have data.

>>> Typically we have API that is either a sub-class of QObject (where the
>>> parent may delete the children, such as QFile) or we have value based
>>> classes (such as QDateTime). There is also a slightly less common,
>>> third model with explicitly shared types, I think mostly acting as
>>> singletons.

>> All of which is mostly about how *the data* is shared.

>>> With QAbstractCalendar there's an entirely new model (which also
>>> includes a clone() method). I think that model should [be]
>>> reconsidered,

>> Can you suggest an alternative ?

Simon Hausmann (31 July 2018 14:34) offered:
> If you are sure that there is no data to be dealt with, that the calendars are
> free of state, then they should probably become singletons.

Well, as I noted, some relatively specialised implementations may need
some data, such as the date at which a country (whose full calendar a
given instance is) made the transition from Julian to Gregorian.

> You can still have a factory on the backend, but for the users of API there
> would be only pointers to calendar objects that are supposed to remain valid
> for the life time of the program.

So you'd be perfectly happy with a pimpl having virtual methods, that a
client-supplied implementation could over-ride ?  Then we could have an
enum on the front-end to select which singleton is saved in the back-end
as the pimpl for each enum member; and client code would register a new
implementation and get back a "user-defined" value of the enum to use in
fetching the instance they passed to the registration.

Or have I mis-understood ?  Because I don't really see how this helps,
when the API the pimpl has to implement is effectively public and you
have exactly the same (theoretical) problem that any change to that is a
backwards-compatibility break for those who have implemented their own
calendars.  So all I see is a bunch of extra bureacracy (the enum and
some mapping from enum members to singletons).  It would seem to make
more sense to simply declare the calendar classes not covered by our
usual backwards compatibility ambitions - albeit with a very high
probability that their API won't ever change.

>>> but if not, then it needs to be documented and it needs to be
>>> clarified how this model applies to the exposure of calendars to
>>> QML. Otherwise you easily risk creating dangling pointers (as pointed
>>> out in the QML review).
>>>
>>> A secondary concern is that the API, once submitted, is not
>>> extensible. We cannot add new properties without breaking binary
>>> compatibility, due to the use of virtual functions in the frontend.

>> Again, please suggest some good ways to do this for the case of
>> calendars, where only rather obscure ones have any data; the differences
>> among widely-used calendars are all in code.

> My preference is the nice-frontend-enum-on-the-backend approach.

Absent a mechanism for extending the enum at run-time, this locks us
down to whatever short-list of calendars we implement in Qt-as-shipped;
which means we'll be under pressure to take in more calendars than we
really want to be left maintaining.  So I'm hoping you're OK with an
"extensible" enum, e.g. one with a UserSupplied = 100 entry and some
mechanism for registering what goes beyond that.  Albeit, as noted
above, I'm failing to see how it really wins us much.

>>> I think in the past we've solved this by having a nice front-end API
>>> with non-virtual functions (those we can add) and channeling this
>>> through to a backend that uses fewer virtual functions but enums (that
>>> can be extended) to dispatch.

>> The problem with that is that you're stuck with the calendars that Qt
>> ships.  We're never going to ship every calendar that the long tail of
>> potential users might want.  We can probably manage the dozen-or-two
>> calendars that the ECMAScript spec mentions in this context, but I want
>> it to be easy for some minority population to be able to implement their
>> own calendar and have Qt transparently use it.  The present design
>> supports that.

> Why does such a separation impose limitations on the API?

I'm failing to understand the question.

>> As an example of the long tail, AIUI, a fully faithful implementation of
>> the islamic calendar (as distinct from the fairly widely-adopted "civil"
>> islamic calendar) needs a distinct calendar for each community.  It
>> would, IIUC, need data about the user's (community's) local ephemrides
>> (when, exactly, the full or new moon is seen rising there, each month);
>> and I want to leave open the option of some population, who want it,
>> doing that for themselves without us having to take in patches for them
>> to get what they want.  There are likewise variants of the Julian
>> calendar still in use by some communities - each its own variant - and I
>> want to let them do their thing in their diverse own ways without us
>> needing to take in patches.  Then, as alluded to above, there's the
>> historians ...
>>
>>> Another alternative is the extension mechanism that we've used with
>>> QFile/QIODevice.
>>
>> I don't know that one.

> It's best demonstrated with the map support in the resource file engine:
>     http://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/io/qresource.cpp#n1482

> A virtual function in the back-end that is lower-level API (not so
> nice to use) but extensible within our constraints. On the frontend
> the API is nice (QFile::map) and it was possible to add this while
> maintaining binary compatibility. It's as if QFile got a new virtual
> function, except it didn't :)

Can you describe how this extension mechanism works, in an overview
style ?  I'm wary of the amount of time it's going to take me to make
sense of this ...

>> I just know that there's a bewildering tangle of
>> abstractions behind QFile, seemingly to handle different file systems,
>> that I sometimes manage to make enough sense of to fix things.  I hope
>> we can avoid having such vast complexity for calendars.  They're not
>> (individually) actually that complicated (well, except for France and
>> Sweden a couple of centuries ago); its the variations between them that
>> complicate life.
>>
>> All of the extension mechanisms you talk about depend on us writing yet
>> another back-end for each supported case.  With calendars, it must be
>> possible for some community to support its own, without needing us to
>> know about it or do more than provide the infrastructure theirs slots
>> into.
>>
>> So yes, the thing I neglected to mention in my previous mail is: do we
>> have any suggestions for how to design an API that'll let app authors
>> implement the calendars they want to support (for their possibly very
>> minority user-bases) and have them work transparently with Qt, just as
>> well as any other calendar that we support ?  Bonus points if there's a
>> way for app-authors to implement a plugin API that lets several of them
>> share the same plugin-implemented calendars (without us having to care
>> how they do it).  The present design does support all of that.
>> Using a classic (but not-so-Qt-ish) C++ virtual method API.

> I don't see a way around achieving this without Qt declaring an interface that
> contains the features it expects the app author supplied calendar to
> implement.

> If we want both, ease of use of calendar API itself as well ease of supplying
> custom calendars to Qt, then we may have to settle for an API that is less
> convenient to use but extensible without breaking source and binary
> compatibility perhaps?

How do we avoid breaking source and binary compatibility for those
clients who've implemented back-ends ?  When, that is, we're making some
change to the design that would otherwise have produced a breakage of
backwards compatibility in the front-end.

I'm also struggling to make sense of what API changes in the front-end
you're imagining, that would be hard to implement without breaking
backwards compatibility.  Calendars have very different kinds of
weirdness from file-systems ...

	Eddy.



More information about the Development mailing list