Hi, I'm currently trying to transform QML value types, such as font, rect, size, etc, into something less random and more predictable. On that occasion I'm wondering what semantics people actually expect from value types.
One thing you have to know in advance is that QML has this internal concept of "value type references". A value type reference is object of a value type combined with a sort of pointer to the property it was retrieved from. Whenever the value type object is modified, it is subsequently written back to its original property. This mechanism is mildly inefficient, as you may imagine. Yet, we use it all over the place. Now, consider the following snippet of QML: import QtQuick QtObject { property font f function doEvil(ff: font) { ff.pointSize = 22 } Component.onCompleted: doEvil(f) } Assume the default pointSize of a font object is 0. What pointSize should the member 'f' of the created object receive here? I see two ways of looking at this: 1. Value types are passed by value ---------------------------------- The doEvil() function then receives a copy of the font and the original font is never modified. Its pointSize stays 0. If this is the way it should behave, you get to tell me what the following should do, though: Component.onCompleted: { var ff = f; ff.pointSize = 22; } In JavaScript, this is indistinguishable from simply "f.pointSize = 22". So, strictly speaking, the latter would have to modify a copy of 'f', not 'f' itself. That, however, would make working with value types somewhat more complicated. You'd have to explicitly write them back after modification. On the plus side, you could modify several properties in a row and only write the value back once. Since value types have been writing themselves back for about 10 years now, we'd need some compatibility mechanism to phase such a behavior in, over several versions of Qt. And I'm sure someone would hate it. However, since we've never implemented value type references for lists, lists of value types behave exactly this way. The following does in fact not modify the list, but only a copy of the object at index 10: property list<font> fonts: [ ... ] Component.onCompleted: fonts[10].pointSize = 33 The same holds for nested value types. Assume a value type "outer" that has a property "a" of another value type, which has an integer property "b". The following does not write back: property outer o Component.onCompleted: o.a.b = 10 2. Everything is a reference ---------------------------- JavaScript doesn't really have value types. The doEvil() function thus receives a reference to the original 'f', not a copy. The modification of pointSize is written back to the original property. With font you might still wrap your head around it because font "looks like" an object with all its properties and internal logic. However, you can also pass a point or a rect around through various functions, and whenever you modify it, the result would be written back to the original place where it was retrieved from, possibly in a different file half an hour ago. I personally find that rather confusing. Another drawback of this is that it would be rather hard to compile a function that deals with value types to C++. In C++, value types don't have a back reference to the property they were loaded from. A QML font is just a QFont and nothing else. This assumption allows qmlcachegen and qmlsc to generate efficient code. Yet, as you may notice by toggling QV4_FORCE_INTERPRETER on the QML program above, they already mess this up today (and no one has noticed). So, the consequence of going with "Everything is a reference" would be that we couldn't compile any function to C++ that passes a value type to a JavaScript function or uses a value type returned from a JavaScript function. A middle ground would be that value types are passed by value when calling or returning from a function, but are treated as references and written back on modification inside a function. Inside the same function qmlsc and qmlcachegen could keep track of where a value was loaded from and write it back when it's modified. I've played with the concept a bit, and it's possible to support nested value types and lists of value types this way. All the writing back would still be inefficient, though. In addition to whatever course is chosen, we might add a detach() method on the JavaScript prototype used for all value types. With that you could intentionally detach a value from the property it was loaded from. regards, Ulf _______________________________________________ Development mailing list Development@qt-project.org https://lists.qt-project.org/listinfo/development