[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