Description
Proposal
Add quote()/noquote() stream modifiers, and an autoQuote() accessor to QDebug class.
Rationale
Piping a QString, QLatin1String, QStringRef, QByteArray object into a QDebug stream automatically quotes the string:
QString s = "Hello World";
qDebug() << s;
leads to
"Hello World"
which is often undesired.
qDebug().noquote() << s;
would print
Hello World
instead.
Existing alternatives
Current alternatives are to either use qDebug in a printf-style way, use qPrintable(), or use toUtf8().constData();
qDebug("%ls", s.utf16());
qDebug() << qPrintable(s);
qDebug() << s.toUtf8().constData();
All of these have draw backs: The printf-style qDebug is more error prone to runtime issues, and does support only printing of POD types. Using qPrintable() is inefficient , and actually does the encoding wrong: it converts toLocal8Bit(), while QDebug expects const char*'s to be UTF-8 encoded. toUtf8().constData() does the encoding right, but is still inefficient, and very verbose.
Precedence
QDebug already features the space(), nospace() modifiers, and an autoInsertSpaces() accessor. "nospace()" is a precedence for not using camel case for the modifier.
Alternative proposals
Generic QDebug::plain(), QDebug::noplain() modifiers
A more general modifier could be e.g. called 'bare()', or 'plain()', and would in general reduce the decorations that QDebug::operator<<s() add:
QStringList strlist; strlist << "Hello" << "World"; qDebug() << strlist; qDebug().plain() << strlist;
could print
("Hello", "World") Hello, World
However, the exact semantics of bare() are then subject to interpretation: Should e.g. the comma separator for lists be removed in this case, too?
Also, such structures can be easily formatted in user code:
QStringList strlist;
qDebug().noquote() << strlist.join("|");
PlainString() class
We could introduce a PlainString container class that gets an extra QDebug::operator<<(const PlainString &str):
qDebug() << PlainString(string);
The structure would need explicit constructors for QString, QLatin1String, QStringRef, QByteArray.
The disadvantage is that it would be yet another 'string related' class in the global namespace. This might be acceptible though if we find a short, but descriptive name...
Impact
Binary Size / Performance
3 exported symbols are added to QDebug, and the size of the private QDebug::Stream structure is increased by a boolean. Furthermore the relevant (inlined) operator<<() methods do need to check for the flag. This means a (slight) code size/runtime penalty for code that does not use the feature. However, performance for existing code that e.g. uses qPrintable(), and is changed to the new API, would benefit.
(Related to that, it should be evaluated whether selected parts of the QDebug class should be made non-inline.).
qPrintable
Since this kills another major use of qPrintable, we might consider deprecating the macro then.
Binary Compatibilty
Since all of QDebug is inlined, there is a risk of BC issues in the following scenarios:
- A QDebug::Stream structure of the old size is created, and passed to code that is compiled with the new version of e.g. operator<<(const QString &).
- A QDebug::Stream structure of the new size is created, and passed to code that is compiled with the new version of e.g. operator<<(const QString &).
Unfortunately the QDebug::Stream structure does not feature a version member. One could 'misuse' the version field in QMessageLogContext though, which is a member of QDebug::Stream.
Source Compatibility
No SC issues are to be expected.