[Development] Convenience Imports in QML

Attila Csipa qt at csipa.in.rs
Mon Dec 17 12:19:00 CET 2012


On 17-Dec-12 00:20, Alan Alpert wrote:
>> I don't necessarily care how different a shiny new API implementation is and
>> if the fact that my application runs on it is purely coincidental based on
>> how I use those APIs, but not having a way to say "YES, I know you bumped an
>> API version, YES, I know there are potential incompatibilities, and YES, I
>> tested it, and YES, it still works" is super-frustrating.
> There's no way to say that because you don't need to say anything in
> that case. If we bump the minor version and it still works (because
> you aren't needing any of the new features) then it will still work
> without you even having to alter your QML code to bump the version you

In theory, that's just fine. The real world throws two wrenches into 
that train of thought:

1. I might want to use the new version if available even I don't use any 
new APIs because the new version is faster, prettier, etc (case in point 
- if my app works w both QtQuick 2.0 and QtQuick 1.1, I want 2.0 if 
available for max performance, but am still fine running on 1.1 if need be).

2. There is no 'requirement' for many modules to be present, much less a 
certain version of them. Which means the future 'compatibility' promise 
I can give for my application (which runs on both) is largely guesswork 
(no way of telling when "play it safe, use QtQuick 1.0" becomes "gamble 
on QtQuick 1.0 presence").

> import. Would the following change help, if import Module x.y chose
> the highest minor version available? So you import QtQuick 1.9, and it
> will fall back to QtQuick 1.1 or 1.0, depending on which is available
> on the system. This sort of functionality is what I think you're
> asking for.

No, that would not help unless there is a set in stone guarantee that a 
minor version bump implies a backward compatibility guarantee (not "best 
effort", "possibility", but *guarantee*), and that a major version bump 
implies major source-level incompatibilities (along the lines of "you 
need to touch source even for a hello world"). Using "1.9" as syntax 
would be confusing to say the least, I would go for import QtQuick 1.* 
or, (even better) import QtQuick 1.0+ (so you could start from a non .0 
version). All this does not solve the problem what if the major version 
IS compatible enough (i.e. QtQuick 1.0 code works without change w 
import QtQuick 2.0). To be able to cover that case, as a minimum, I'd 
like to see

import QtQuick 2.0, QtQuick 1.0+

(listing just versions is not enough - as library/plugin names can 
change, or I want to fall back to a different namespace)

And as said, this is just the first step - small version bumps are no 
smaller problem than major version bumps. For example QtQuick 1.1 
introduced a couple of (non-critical) extra properties for the Text {} 
element. Your choices are "go for 1.0, forget the feature", "go for 1.1, 
forget the 1.0 devices", or "clone QMLs or blow up the whole thing with 
component loaders". All that fuss for one measly property - and we're 
not even talking about compiled code. Whole components are even worse.

It's a bit scary that I while I don't ifdef as much any more, I find it 
compelling to keep everything in separate git branches and solve all 
this with various git magic because the QML versioning/component/import 
syntax, as is, just can't cope with any (larger-scale) real life cross 
multi-device/multi-Qt version deployment. Why ifdef when you can git 
cherrypick/merge, right ? I already started seeing code snippets like

#ifdef platform-or-qt-version-this
         viewer.setMainQmlFile(QLatin1String("qml/qtq2main.qml"));
#elif different-platform-or-qt-version
         viewer.setMainQmlFile(QLatin1String("qml/qtq1main.qml"));
#else
         viewer.setMainQmlFile(QLatin1String("qml/justincase.qml"));
#endif

where the three qml files differ in only - you guessed it - in the 
import statement. That's *got* to be wrong.

> Note that the way the versioning system is implemented it is easy (and
> strongly encouraged) to provide all minor versions of the module in
> the package for that major version. So anywhere that supports QtQuick
> 1.1 should also support previous minor versions, like QtQuick 1.0.
> That isn't strictly enforced by the engine, but should be enforced by
> convention and the engine deliberately makes that case easy. As for
> major versions, those are expected to be wildly different and
> developers need to make a choice of major version explicitly, so not
> being able to run the same code between QtQuick 1.x and QtQuick 2.x is

I'm repeating myself, but... The problem with this is that in the 4.x 
(or, C++ days) we had this minor version guarantee, an I guess I would 
expect a Qt 5.1 to be backwards compatible with Qt 5.0 on the C++ level. 
This promise, IIUC, does not hold for the QML APIs - if deemed 
necessary, a major version will be bumped - unfortunately there is no 
way to make this easier for the *developer* (with the current versioning 
approach you're taking away the ability to support a *range* of 
versions, pushing people to support a *single* version even if they 
*could* do more with ease).

> expected. It's like how you have to compile against Qt4 or Qt5, you
> can't run the same binary against both (but because QML is an
> interpreted language, the choice has to be made at runtime based on
> the import statements). Eventually people will stop shipping Qt 4 and
> then you'll need to provide your own if you want to keep running a Qt4
> app - same with QtQuick 1. If the problem is that QtQuick 2 (or Qt 5
> for that matter) looks so close that you thinks you *should* be able
> to run the same code with the previous version, then you should be
> disputing the choice to increment the major version instead of the
> minor version.

I encourage you to go to qt5\examples\declarative and see how many of 
the pure QML applications will continue to work if you change import 
QtQuick 1.0 to 2.0. Not counting the ones using particles, surprisingly 
many. I'd like to think it's a testament to a good level of 
compatibility (which is desired and very welcome, helping/easing the 
transition to 2.0), rather than misnaming a 1.3 into 2.0 (and given how 
fragile the compatibility guarantee is there, I have no qualm of it 
being called 2.0, my beef* is very strictly with the versioning logic as 
implemented - it's not as bad as Flash, which made me write 
tweakflashver, but sadly not that far from it, either).


Best regards,
Attila



More information about the Development mailing list