Hi,

I'd like to continue the discussion started by Marc and try to find out what 
should be the "fate" of our literal operators.

For the reasons explained by Marc, we've added _L1 to Qt::inline 
Literals::inline StringLiterals namespace, but we still have the literals 
operators _qs (for QString) and _qba (for QByteArray) in the global inline 
QtLiterals namespace. This is clearly inconsistent, so the next logical step is 
to move _qs to _qba to Qt::inline Literals::inline StringLiterals too. This 
assumes:


  *   Adding Qt::inline Literals::inline StringLiterals ::{_s, _ba} 
(https://codereview.qt-project.org/c/qt/qtbase/+/401308)
  *   Deprecating _qs and _qba 
(https://codereview.qt-project.org/c/qt/qtbase/+/401604)

As you can see, https://codereview.qt-project.org/c/qt/qtbase/+/401604 raised a 
lot of discussion, and not everyone felt comfortable with deprecating (and 
later removing) the "q"-prefixed UDLs.
To summarize the discussion, I see following options:


  1.  deprecate  _qs, _qba, add Qt::StringLiterals::{_s, _ba}, as suggested 
above (https://codereview.qt-project.org/c/qt/qtbase/+/401308 + 
https://codereview.qt-project.org/c/qt/qtbase/+/401604)
  2.  keep _qs, _qba, add_qL1 and remove Qt::StringLiterals::_L1 
(https://codereview.qt-project.org/c/qt/qtbase/+/402948 + 
https://codereview.qt-project.org/c/qt/qtbase/+/402950)
  3.  keep _qs, _qba, add _qL1, keep Qt::StringLiterals::_L1, add 
Qt::StringLiterals::{_s, _ba} 
(https://codereview.qt-project.org/c/qt/qtbase/+/402948 + 
https://codereview.qt-project.org/c/qt/qtbase/+/401308)

I personally prefer the 1st option, but it would be nice to hear more 
opinions/concerns and decide how to proceed.

Thanks,
Sona

From: Development <development-boun...@qt-project.org> On Behalf Of Marc Mutz
Sent: Tuesday, March 29, 2022 4:31 PM
To: development@qt-project.org
Subject: Re: [Development] Renaming QLatin1String to QLatin1StringView

Hi all,

There seems to be some confusion over the form the literal operators ("UDLs") 
have taken: Qt::inline Literals::inline StringLiterals::_L1 instead of inline 
QtLiterals::_qL1.

There are several reasons for doing it this way, and it's important for any 
follow-up discussions to understand them, so bear with me as I lay them out:


  1.  UDLs are operators, and as operators, the usual way to call them is with 
unqualified calls: a + b may be seen by the compiler as NS::operator+(a, b), 
but that's not how we'd like to write our code. So, we'd like to use "meep"_L1, 
not QtLiterals::operator""_L1("meep", 4), assuming the latter is even valid C++.
  2.  All unqualified function calls in C++ always consider all overloads that 
are in scope. If two of them conflict (are ambiguous), as an API consumer, you 
have three ways to fix this:

     *   change the arguments (e.g. by casting) to avoid the ambiguity (not 
possible for UDLs, because the argument must always be a string, integer, or 
floating-point literal)
     *   use a qualified call (foo() -> NS1::foo() or NS2::foo(), depending on 
which one you want; undesirable for UDLs, as per point (1))
     *   change the scope so as to remove one of the conflicting overloads 
while leaving the other (this is what namespaces were designed for): Instead of 
"using namespace NS1; using namespace NS2; foo();", you do "using namespace 
NS1; foo();"

  1.  Seeing as (a) and (b) are not applicable for UDLs, (c) is the only 
option. This is why std arranges its UDLs that way, and that's why we chose to 
do the same for _L1. It allows API consumers to pick Qt's _L1 or some other 
(presumably their own), by adding or removing using directives. The 
disadvantage is that you cannot access these UDLs (std or Qt's) without first 
writing a using directive. This is a necessary evil, though:
  2.  We have prior art (_qs) which does things differently: ::inline 
QtLiterals::_qs. This UDL is declared in an inline namespace hanging in the 
global namespace. That means we don't need to write a using directive to be 
able to use it, but it also means API consumers cannot switch it off. It's 
always in-scope. If they now have a conflict, all they can do is to move the 
code to a separate .cpp file to include less headers or to not use the 
conflicting UDL. The conflict is unfixable using normal means, which is why we 
need to use an additona; character, the q prefix, to limit possible conflicts. 
But we can't eliminate them. As a physicist, it's not hard to come up with UDLs 
that start with q: _qcd, _quant, ... We like to think that Qt owns the q 
prefix, but it doesn't (qsort), so it's just a way to make clashes less likely. 
With KDE adopting the same strategy with a different letter, we already claim 
1/13th of the available C++ namespace! The only reason why we got away with it, 
so far, is that we don't use very short function names like qs(), qe(), etc. 
But that's exactly what we've introduced with _qs, and it's why it should be 
fixed.
  3.  UDLs should be short at the use site, because we want people to use them. 
If not for their brevity, they carry no value over traditional constructor 
syntax: "meep"_L1 vs. QLatin1StringView("meep"). There is absolutely no sense 
in long UDLs like "meep"_qlatin1stringview, and even _qs vs. _s matters in that 
respect (it's a 50% increase in the identifier name!)
  4.  Any project should be able to decide for itself how to handle UDLs. Some 
may choose to require using declarations in every function or every scope a UDL 
is used, some may require it at namespace scope of every implementation file, 
some may add it to some central header (which is ok for an app, but not for a 
library, cf. SF.7 
(https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines.html#Rs-using-directive)).
 The point is: we need to allow users to make their own choice. By adding our 
UDLs to ::inline QtLiterals, we deprive them of that choice, and we potentially 
break their code in unfixable ways. We even allow users to switch off 'signals' 
and 'slots' macros, but users wouldn't be able to switch off our UDLs.
This is why they need to be in Qt::inline Literals::inline StringLiterals. 
Anchoring the inline namespaces (which here are just for convenience, so you 
can alternatively say "using Qt::Literals" or "using Qt::StringLiterals" or 
"using Qt::Literals::StringLiterals") in the non-inline Qt namespace makes it 
possible for API consumers to switch them off.

In addition to the above the nested StringLiterals namespace gives us the 
flexibility to add (short!) UDLs for non-string domains, later, without 
conflict. E.g. std has s for seconds as well as for std::string. We should just 
copy what works instead of inventing creative ways to break users.

Thanks,
Marc


________________________________
From: Development 
<development-boun...@qt-project.org<mailto:development-boun...@qt-project.org>> 
on behalf of Sona Kurazyan <sona.kuraz...@qt.io<mailto:sona.kuraz...@qt.io>>
Sent: Friday, March 11, 2022 5:26 PM
To: Macieira, Thiago 
<thiago.macie...@intel.com<mailto:thiago.macie...@intel.com>>; 
development@qt-project.org<mailto:development@qt-project.org> 
<development@qt-project.org<mailto:development@qt-project.org>>
Subject: Re: [Development] Renaming QLatin1String to QLatin1StringView

> BTW, shouldn't this one also have a "v" somewhere, like _qsv?

If there's a chance of adding an owning class for Latin-1 in future, it might 
make sense to reserve _L1 for it and add "v" for QLatin1StringView literal.
On the other hand, we can call the literal operator for the owning class _L1s, 
and save some typing for the QLatin1StringView users (which, I guess, would be 
more common to use).

Best regards,
Sona

> -----Original Message-----
> From: Development 
> <development-boun...@qt-project.org<mailto:development-boun...@qt-project.org>>
>  On Behalf Of
> Thiago Macieira
> Sent: Friday, March 11, 2022 4:39 PM
> To: development@qt-project.org<mailto:development@qt-project.org>
> Subject: Re: [Development] Renaming QLatin1String to QLatin1StringView
>
> On Friday, 11 March 2022 00:46:16 PST Sona Kurazyan wrote:
> > s. In Qt 7, QLatin1StringView will become "the real" class for Latin-1
> > string view, and QLatin1String will be kept as alias to it.
>
> I'd like to say I support this, at least as far as 7.0 with just the alias.
>
> When or if ever we drop the QLatin1String name and even if we ever add a
> new class is a subject for much later and doesn't have to be taken now. But
> unless we do the change Sona is proposing now, we that option wouldn't be
> on the table.
>
> > Note that Qt 6.4 introduces a literal operator""_L1 for constructing
> > Latin-1 string literals, to minimize the porting effort from
> > QLatin1String to QLatin1StringView.
>
> BTW, shouldn't this one also have a "v" somewhere, like _qsv?
>
> --
> Thiago Macieira - thiago.macieira (AT) intel.com
>   Software Architect - Intel DPG Cloud Engineering
>
>
>
> _______________________________________________
> Development mailing list
> Development@qt-project.org<mailto:Development@qt-project.org>
> https://lists.qt-project.org/listinfo/development
_______________________________________________
Development mailing list
Development@qt-project.org<mailto:Development@qt-project.org>
https://lists.qt-project.org/listinfo/development
_______________________________________________
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development

Reply via email to