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();"
  3.  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:
  4.  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.
  5.  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!)
  6.  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 <[email protected]> on behalf of Sona 
Kurazyan <[email protected]>
Sent: Friday, March 11, 2022 5:26 PM
To: Macieira, Thiago <[email protected]>; [email protected] 
<[email protected]>
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 <[email protected]> On Behalf Of
> Thiago Macieira
> Sent: Friday, March 11, 2022 4:39 PM
> To: [email protected]
> 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
> [email protected]
> https://lists.qt-project.org/listinfo/development
_______________________________________________
Development mailing list
[email protected]
https://lists.qt-project.org/listinfo/development
_______________________________________________
Development mailing list
[email protected]
https://lists.qt-project.org/listinfo/development

Reply via email to