[Development] RFC: Proposal for a semi-radical change in Qt APIs taking strings

Knoll Lars Lars.Knoll at theqtcompany.com
Wed Oct 14 08:37:19 CEST 2015


I’m not a huge fan of having different overloads with QString, QStringRef
and QLatin1String and in some cases (QChar *, int) for many methods
neither. But while your proposal solves some problems it introduces others.

A QStringView class would only work for methods that read the data
contained in it, but don’t try to modify it or take a copy (as Thiago
pointed out). And you certainly can’t keep the pointer to the data around
for longer than the lifetime of the QStringView, so it’s to some extent an
advanced class you have to be careful when using in your own APIs.

So it can work nicely for methods such as QString::indexOf and similar,
but will never be good for methods that need to copy the string (e.g.
QUrl::setHostName).


Another thing I wonder about is whether we shouldn’t deprecate
QLatin1String moving forward. We have QStringLiteral, and even though it’s
implementation is not ideal, we should be able to get it working
everywhere now with Qt 5.7. Let’s think about how and whether we can
improve it’s implementation to fix the remaining issues. Then we could
remove/deprecate QLatin1String.

On 13/10/15 23:01, "Thiago Macieira" <thiago.macieira at intel.com> wrote:

>On Tuesday 13 October 2015 22:46:36 Marc Mutz wrote:
>> Q: What mistakes do you refer to?
>> 
>> A: The fact that it has copy ctor and assignment operator, so it's not a
>> trivally-copyable type and thus cannot efficiently passed by-value. It
>>may
>> also be too large for pass-by-value due to the rather useless QString
>> pointer (should have been QStringData*, if any). Neither can be fixed
>> before Qt 6.
>
>Not even in Qt 6. The reason why it uses a QString pointer is that it
>follows 
>the QString through reallocations. If the QString is mutated, the
>QStringRef 
>will still be valid (provided it isn't shortened beyond the substring the
>QStringRef points to). There's a lot of code that depends on this, so we
>can't 
>change it.

Only by deprecating QStringRef and not using it ourselves anymore. But
it’s used quite a lot in Qt, so this is no easy job and will certainly
break source compatibility in places such as the XML stream reader.
>
>> Q: Why size_t?
>> 
>> A: The intent of QStringView (and std::experimental::string_view) is to
>>act
>> as an interface between modules written with different compilers and
>> different flags. A std::string will never be compatible between
>>compilers
>> or even just different flags, but a simple struct {char*, size_t} will
>> always be, by way of it's C compatibility.
>> 
>> So the goal is not just to accept QString, QStringRef, and (QChar*,int)
>>(and
>> QVarLengthArray<QChar>!) as input to QStringView, but also
>> std::basic_string<char16_t> and std::vector<char16_t>.
>
>The C++ committee's current stance on signed vs unsigned is that you
>should 
>use signed for everything, except when you want to have modulo-2
>overflows. 
>We're not overflowing, so it should be signed.

Yes, signed please. We can discuss whether it should be 64bit for Qt 6.

>
>> Q: What future do you have in mind for QStringRef?
>> 
>> A: None in particular, though I have found a need for an owning
>>QStringRef
>> in some places. But I expect Qt 6' QString to be able to provide a
>> restricted view on shared data, such that it would subsume QStringRef
>> completely.
>
>We should deprecate it if QStringView comes into being.

Agree. 
>
>> Q: What about QLatin1String?
>> 
>> A: Once QString is backed by UTF-8, latin-1 ceases to be a special
>>charset.
>> We might want something like QUsAsciiString, but it would just be a
>>UTF-8
>> string, so it could be packed into QStringView.
>
>Since QString will not be backed by UTF-8, the answer is irrelevant.

Agree here as well. We can’t make QString utf-8 backed without breaking
way too much code. I also don’t see the need for it. The native encoding
on Windows and Mac (Cocoa) is utf-16 as well, on Linux it’s utf-8. So no
matter which platform we’re on, we won’t avoid some conversions.

And I will strongly oppose any attempts to make QString some sort of
hybrid supporting both. The added complexity in maintaining the code base
is simply not worth it.

>
>> Q: What about QByteArray, QVector?
>> 
>> A: I'm unsure about QByteArrayView. It might not pull its weight
>>compared to
>> std::(experimental::)string_view, but I also note that we're currently
>> missing a QByteArrayRef, so a QBAView might make sense while we wait for
>> the std one to become available to us.
>
>Given the mistakes that you and I are pointing out in QStringRef, we
>should 
>not add QByteArrayRef. Instead, it should be in the new-style, in which
>case I 
>wonder whether we should add a class in the first place. And moreover,
>how 
>often is this needed? std::array_view should be plenty for QByteArray and
>QVector where needed.

Agreed as well.
>
>> I'm actively opposed to a QArrayView, because I don't think it provides
>>us
>> with anything std::(experimental::)array_view doesn't already.
>
>Right.
>
>> Q: What do you mean when you say "abandon QString"?
>> 
>> A: I mean that functions should not take QStrings as arguments, but
>> QStringViews. Then users can transparently pass QString, QStringRef and
>>any
>> of a number of other "string" types without overloading the function on
>> each of them.
>> 
>> I do not mean to abandon QString, the class. Only QString, the interface
>> type.
>
>I'm not agreeing to the proposal just yet.
>
>But as a condition to be even considered, it needs to be only for the
>methods 
>that do not hold a copy of the string. That is, methods that immediately
>consume the string and no longer need to reference its contents.
>
>Methods that keep a copy for any reason (e.g., QFile::setFilename) should
>still keep a QString API so that they can participate in the reference
>counting.

Yes, we can’t do it differently. That immediately brings up the problem of
how to make things future proof. Suppose we have an API that takes a
QStringView because we’re not taking a copy of the string. Two minor
releases later we find out that we need a copy for some reason
nevertheless. What do we do?

I’m not saying that a QStringView might not be a good idea, but we have to
be careful where we use it. I’d say that for most cases we want to
continue to pass a const QString & into the methods. QStringView would be
reserved for performance critical parts of the API, which 90% of our API
is not.

Cheers,
Lars

>
>> Q: What API should QStringView have?
>> 
>> A: Since it's mainly an interface type, it should have implicit
>>conversions
>> from all kinds of "string" types, but explicit conversion _to_ those
>>string
>> types. It should carry all the API from QString that can be implemented
>>on
>> just a (QChar*, size_t) (e.g. trimmed(), left(), mid(), section(),
>>split(),
>> but not append(), replace() (except maybe the (QChar,QChar) overload.
>> Corresponding QString/Ref API could (eventually) just forward to the
>> QStringView one.
>
>That makes sense.
>
>-- 
>Thiago Macieira - thiago.macieira (AT) intel.com
>  Software Architect - Intel Open Source Technology Center
>
>_______________________________________________
>Development mailing list
>Development at qt-project.org
>http://lists.qt-project.org/mailman/listinfo/development



More information about the Development mailing list