Details
-
Task
-
Resolution: Won't Do
-
P2: Important
-
None
Description
In a future version of the QML language, we can drop the concept of grouped properties. Grouped properties are problematic because they violate encapsulation by letting outer components access internals of their children. Grouped properties also are responsible for a lot of complexity in our QML implementation.
To replace grouped properties, the objects being set up should be passed wholesale to the component being instantiated. Currently you can do the following:
Text {
font.bold: true
}
This would be replaced with:
Text {
font: Font { bold: true }
}
As the explicit specification of "Font" is redundant here, we can add a shorthand syntax for this, which would deliberately have different semantics than the current grouped properties:
Text {
font { bold: true }
}
The straight dot syntax shown in the first example should be removed, though, to make it clear that the user is not initializing an existing object in place, but rather creating a new one.
This would mean that all the current internals like anchors, font, etc. need to be createable from QML, and assignable. In turn we can then set up a policy to have those internals be nullptr by default, saving some effort on initialization.
However, the most common use cases of grouped properties right now are anchors in Item and font in various text-related elements. Mandating a source-incompatible change for all of those may be too much. Therefore, another way out of this may be an explicit declaration of a property to be grouped:
A { grouped property Font font }
Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged GROUPED)
This would mean that the property in question can be accessed as grouped property like "font.bold: true", but it does not get an identity independent of the enclosing object anymore. Therefore, assigning "font: Qt.font(...)" would not replace the Font object, but rather invoke it's assignment operator or copy all its properties individually. This way, many of the inconsistencies could be resolved in an elegant way. In particular:
RR {
grouped property Rectangle rect: Rectangle { property int i: 5 }
}
This would not retain the "i" property, as only the base rectangle would be copied, not the extension declared inline. Or, it wouldn't work at all as you'd call the equivalent of "*nullptr = QQuickRectangle(...)".
A {
Rectangle {
id: rrr
property int i: 5
}
grouped property Rectangle rect: rrr
}
rrr != rect after this, as Rectangle is not a value type and "!=" compares identity. Also, rect doesn't have a property i.
If a property is not grouped, any grouped assignment would lead to a warning in 5.15, and be prohibited in QML 3. There are some open questions, though:
A { // What exactly can we do with this? // Proposal: Nothing, as "var" doesn't declare any properties grouped property var jsobj: ({ a : 5 }) // Same? grouped property variant varobj }
RR {
rect: Rectangle { y: 40 }
// Allowed? Precedence? What if we do this with multiple levels of grouped properties from different files?
rect.x: 50
}
Attachments
Issue Links
- depends on
-
QTBUG-76887 Make object overrides more optimal
- Open
-
QTBUG-79330 Improve handling of Q_GADGETs in QML
- Open
-
QTBUG-79382 Add support for inline components
- Closed
- is replaced by
-
QTBUG-82766 Uncontrolled aliasing of data via grouped properties and aliases
- Open
- is required for
-
QTBUG-73675 Streamline QML for better toolability and performance
- Open
- relates to
-
QTBUG-66632 Aliases to id objects have the wrong type if the object declares properties
- Closed
-
QTBUG-73932 Custom font in component not shown in form viewer
- Closed