Hi,
> Is it to change the setter/getter function? Would that not better be solved making the setter/getter virtual on the C++ side and removing the "overriden" property? We intend to also add some more guidance when you want to do this to the docs, but in general your assessment is correct: if you can solve the issue at the C++ level, that's probably the better place. We have however encountered a few cases where this is necessary, or the least bad solution: - turning a writable property read-only and vice-versa (the most prominent example being Item's implicitWidth). Removing writability is still fishy in my opinion (implicitWidth notwithstanding), but adding it in a subclass is arguably fine from a type theory point of view (as it's less restrictive). - changing the type of a property in a way not compatible with C++ polymorphism (used to be more important when we hadn't support for int64 at all in the engine, but in a base lib usable with Widgets, you might still want a `std::optional<int>` property in the C++, but expose a QJSValue (which can be undefined under the same name to QML) - allowing the narrowing possible in C++ in QML, as in have a property that's always an Item in a C++ base, but guarantee that it's a Rectangle in a QML derived type. You might also have cases where you believe that shadowing is generally a terrible idea, but where a search on open source repositories shows that tons of projects have in fact shadowed it. In that case, you can mark the base property as virtual, which causes an unconditional warning – and if those projects really intended to shadow it, they can then add override, and it is fine(ish). Kind regards, Fabian ________________________________________ Von: Development <[email protected]> im Auftrag von Albert Astals Cid <[email protected]> Gesendet: Dienstag, 24. Februar 2026 19:37 An: [email protected] Betreff: Re: [Development] shadowing properties (and methods) El dimarts, 24 de febrer del 2026, a les 15:57:39 (Hora estàndard d’Europa central), Ulf Hermann via Development va escriure: > Greetings and Salutations, > > As some of you may know, QMetaObject has a problem with what we call > "shadowing". Consider: > > class Base > { > Q_OBJECT > Q_PROPERTY(int a READ a CONSTANT) > > public: > int a() const { return 4; } > > Q_INVOKABLE int b() const { return 5; } > }; > > class Derived : public Base > { > Q_OBJECT > Q_PROPERTY(int a READ a CONSTANT) // shadows Base::a > > public: > int a() const { return 6; } > > // Shadows Base::b > Q_INVOKABLE int b() const { return 7; } > }; > > Now when you get a Base* and retrieve its property "a" or call its > method "b" via the QMetaObject, you don't actually know which property > you are retrieving or which method you are calling. > > From C++ you can introspect the QMetaObject hierarchy and determine > what property or method you're dealing with. This is much more > complicated than the usual way of simply doing > someObject->property("a"), though. > > From QML, you can't. QML will always use the most-derived QMetaObject > that has the property or method. You can shadow properties and methods > further in QML, and most egregiously, you can shadow properties with > methods and vice versa. This is rather dangerous because we internally > rely on many of the properties of, say QQuickItem, to actually assume > the values we set on them. If you shadow a property like > QQuickItem::data, you're certainly in for some surprises. It is quite > common to add a property called "data" to one of your custom types, > though. So, this is inviting some serious foot archery. For fun and > confusion, try the following: > > // Base.qml > import QtQuick > Item { > id: root > property int data > } > > // Derived.qml > import QtQuick > Base{ > Rectangle {} > } > > This results in the following warning: > > Derived.qml:3:4: Cannot assign value of type "Rectangle" to property > "data", expecting "int" > > We've recognized this as a problem a long time ago and introduced the > FINAL attribute to Q_PROPERTY. The FINAL attribute only takes effect if > you use QML. If you shadow a FINAL property in pure C++, it does nothing > (unfortunately). However, if you try to use a *shadowed* FINAL property > in QML you get a warning or an error, depending on the context. We can't > really do better than this for FINAL alone. You can call moc on Base and > Derived independently, and you can re-moc Base after building Derived. > This way you can sneakily introduce a FINAL after the derived type > already exists. So we have to accept some fuzziness there. It follows > that also in QML we can't flat out reject all your shadowed properties. > We can just assume they are not shadowed and still use the base type's > properties in case they are. > > On top of all this complication, however, the presence of FINAL is not > quite enough because you have to remember to add FINAL to every property > that's eligible for finality. Keeping track of this is messy and > error-prone. As a result, few properties are FINAL in practice, even if > most should be. > > C++, back in the day, had a similar problem with virtual methods. When > you declared a method in a derived type, you'd have to look up all the > methods in all base types to figure out if the method you were declaring > was virtual by inheritance. This was error-prone. You could accidentally > introduce overriding methods that weren't meant to be virtual and vice > versa. > > In C++, this was solved by introducing the "override" and "final" > keywords to mark methods that are intentionally overriding a virtual > one. The introduction of the "override" and "final" keywords came with a > number of warnings and errors that now steer you towards adding the new > keywords to all methods that intentionally override, and only those. > > In Qt 6.11, we're doing the same to Q_PROPERTY. In addition to FINAL, > you can now add attributes VIRTUAL and OVERRIDE to mark properties that > are intended to be overridden and ones that intentionally override a > virtual property. Can you give an example of why one would want a virtual/override property? Is it to change the setter/getter function? Would that not better be solved making the setter/getter virtual on the C++ side and removing the "overriden" property? Cheers, Albert > Likewise, in QML you can mark properties with the > "virtual", "override", and "final" keywords. If you use those new > attributes and keywords, you get appropriate warnings and errors in QML > (but not in C++, because see above). If you don't use them, you don't > get warned ... yet. This is because we haven't adapted all of Qt to be > free of those warnings, yet. > > We still highly recommend you clean up unintended shadowing and use the > new keywords and attributes where applicable already in Qt 6.11. You can > get warned about shadowing properties without the new keywords and > attributes by enabling debug messages from the > qt.qml.propertyCache.append logging category. For example with an > environment variable like this: > > QT_LOGGING_RULES="qt.qml.propertyCache.append.debug=true" > > For Qt 6.12, we are planning to enable these warnings by default. Among > other things, this will mean that you will get warned when shadowing > properties from Qt types that aren't meant to be shadowed. > > In addition, we are planning to resolve the issue of shadowing methods > and shadowing properties with methods in a similar way. We don't know > when this will be ready, though. > > best regards, > Ulf -- Development mailing list [email protected] https://lists.qt-project.org/listinfo/development -- Development mailing list [email protected] https://lists.qt-project.org/listinfo/development
