[Development] Views (was: Re: QList for Qt 6)
Thiago Macieira
thiago.macieira at intel.com
Thu May 16 18:29:11 CEST 2019
On Thursday, 16 May 2019 08:26:08 PDT Mutz, Marc via Development wrote:
> > That goes against the Qt API design. Do not return views, since it
> > implies
> > that internally there is an object that produces that view and that it
> > does
> > not go out of scope. The reason we return full, owning containers is so
> > we
> > have the freedom inside to change how we store the data without that
> > affecting
> > our API.
>
> I believe the opposite to be true: I believe owning container use in the
> API to break a class' encapsulation:
>
> If you return QVector<>, which choices do you have for the internal data
> structure? A QVector.
When you first design the class, sure. But 5 years later, you may have the
data internally kept in a QMap or QHash, mapped to some other information. So
your function that used to "return d->member;" now does
"return d->member.keys();"
Another case would be where you're keeping extra data in the internal
structure and you need to filter that out before returning. Or the dual:
augment with some implied data. The latter could be quite common if the class
is not storing anything in the regular case, but synthesising it on demand for
the benefit of the old API.
> If you return a view, you can use a std::vector, a QVector, a C array
> internally, even switch at runtime (like QRegion does for the case of a
> single rect). So views allow the implementation to vary its internal
> data storage strategy while returning owning containers does not.
But only so long as each of those containers store lay the data out the same
way in memory, which is not the case for my QMap example.
> And no, you _can_ write views for node-based containers, too. Cf. how
> QVariant is (indirectly) iterable these days.
Sure, but you'd have to change the public API to return that view instead of
the contiguous-storage one. Unless we predict that that would be the case and
always return a view that uses an indirect data-access method, which
potentially owns the data. Does such a view exist?
> Sure, you'd not return a view to data that the class in question does
> not already own, though with coroutines you could return a generator
> instead. This is about the data that is already stored in the object.
> This is about QRegion::rects() and QGradient::stops(). This is also
> about QAIM::roleNames(). All these APIs lock down the implementation to
> a particular data store, thus _reducing_ the implementation's freedom to
> adjust it's internal workings. And by Hyrum's Law, they also make users
> depend on idiosyncrasies of the implementation, as witnessed by the
> pre-QRegion::begin/end() anti-pattern of abusing boundingRect() when
> rectCount() == 1 in order to avoid the building of a QVector just to
> store one rectangle, a special-casing I could remove in 100% of cases
> once QRegion became iterable (= a view on it's rects property).
Two of your examples basically return an internal structure, so I'm not seeing
how they are relevant. QGradient::stops is a good example that synthesises
data on-demand in one case:
if (m_stops.isEmpty()) {
QGradientStops tmp;
tmp << QGradientStop(0, Qt::black) << QGradientStop(1, Qt::white);
return tmp;
}
return m_stops;
How would you implement this one with a view-based return?
--
Thiago Macieira - thiago.macieira (AT) intel.com
Software Architect - Intel System Software Products
More information about the Development
mailing list