Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-15 Thread Thiago Macieira
On Wednesday, 15 November 2023 08:32:40 PST Marc Mutz via Development wrote:
> All other std::regular Qt classes will be using the new types (or, if
> helper functions are inline and we compile in C++20 mode, the std types
> directly).

Please remember you must not change the return type of any exported function.

So I advise we just use the Qt types and come Qt 7 they become a typedef. 
There's no need to use the Standard types right now.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-15 Thread Marc Mutz via Development
I feel we're turning in circles here, so let me give a rundown of what I 
thought we might meet at:

- Introduce Qt::{partial,weak,strong}_ordering
   - BC and SC-as-much-as-possible to std::*_ordering
   - Qt 7: Qt::foo_ordering becomes a typedef for std::foo_ordering, 
like QPair in Qt 6
- QPartialOrdering stays as-is
   - except it gets implicit conversions to Qt::_ordering types
   - (undecided) ditto _to_ Qt::_ordering types

This means QVariant and QMetaType keep using QPartialOrdering, but 
that's ok, they're anyway type-erased, so some overhead is expected. 
QVariant, in particular, only has a static compare() function that 
returns QPartialOrdering. An eventual compareThreeWay() would return 
Qt::partial_ordering.

All other std::regular Qt classes will be using the new types (or, if 
helper functions are inline and we compile in C++20 mode, the std types 
directly).

On 14.11.23 18:20, Thiago Macieira wrote:
> On Tuesday, 14 November 2023 08:25:34 PST Ivan Solovev via Development wrote:
>>> The ABI functions can return one of these other types:
>>>   bool  (for equality comparisons)
>>>   int  (for non-partial ordering)
>>>   QPartialOrdering (for partial ordering)
>>
>> IIUC, returning QPartialOrdering is exactly what we want to avoid, due to
>> the std::partial_ordering -> QPartialOrdering (and reverse) conversions.
> 
> That boat sailed in 6.1 because QPartialOrdering is already used in QMetaType
> and QVariant API/ABI.

As per the above, these classes can continue to use QPO. QVariant, in 
particular, when ported to the new macros, will use Qt::partial_ordering 
in compareThreeWay() and QPO in compare(). Shit happens.

> Ideally for new out-of-line APIs, we could return a type that is ABI-
> compatible with std::partial_order.

That are the Qt::_ordering types, yes.

> But how many of those are we going to get?

Every ordered Qt class. I didn't count, but sufficiently many to matter.

>> As we figured out earlier in this discussion, by making Qt::partial_ordering
>> binary compatible with std::partial_ordering, we will allow the compiler to
>> optimize the code and avoid the conversions (specially if we use
>> std::bit_cast).
> 
> Yes, but the impact only applies to when it needs to translate from out-of-
> line to out-of-line. If either side is inline, it'll do the right thing on its
> own.

Yes. If either side is inline, you still get the conversion operators 
emitted in debug mode, which Qt tends to optimize for, too. That's one 
of the reasons why, even with {std,Qt}::_ordering types being BC to each 
other, it makes sense to return std in C++20 builds and Qt in C++17 builds.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Giuseppe D'Angelo via Development

Il 14/11/23 09:12, Marc Mutz via Development ha scritto:

Given that this is an API that is going to stay with us for at least a decade,
I'd rather get it right than getting it soon.

We're discussing various tangential aspects for half a year now. At some
point, all the cards are on the table and all that talking needs to come
to some conclusion.

That point is now.


Could this long thread be summarized somehow? I'm really unsure on the 
conclusions. I'd also welcome a discussion for QtCS, if it wasn't so 
close to the FF.


--
Giuseppe D'Angelo | giuseppe.dang...@kdab.com | Senior Software Engineer
KDAB (France) S.A.S., a KDAB Group company
Tel. France +33 (0)4 90 84 08 53, http://www.kdab.com
KDAB - The Qt, C++ and OpenGL Experts



smime.p7s
Description: Firma crittografica S/MIME
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Thiago Macieira
On Tuesday, 14 November 2023 08:25:34 PST Ivan Solovev via Development wrote:
> > The ABI functions can return one of these other types:
> >  bool  (for equality comparisons)
> >  int  (for non-partial ordering)
> >  QPartialOrdering (for partial ordering)
> 
> IIUC, returning QPartialOrdering is exactly what we want to avoid, due to
> the std::partial_ordering -> QPartialOrdering (and reverse) conversions.

That boat sailed in 6.1 because QPartialOrdering is already used in QMetaType 
and QVariant API/ABI.

Ideally for new out-of-line APIs, we could return a type that is ABI-
compatible with std::partial_order. But how many of those are we going to get?

> As we figured out earlier in this discussion, by making Qt::partial_ordering
> binary compatible with std::partial_ordering, we will allow the compiler to
> optimize the code and avoid the conversions (specially if we use
> std::bit_cast).

Yes, but the impact only applies to when it needs to translate from out-of-
line to out-of-line. If either side is inline, it'll do the right thing on its 
own.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Ivan Solovev via Development
> The ABI functions can return one of these other types:
>  bool  (for equality comparisons)
>  int  (for non-partial ordering)
>  QPartialOrdering (for partial ordering)

IIUC, returning QPartialOrdering is exactly what we want to avoid, due to the
std::partial_ordering -> QPartialOrdering (and reverse) conversions.

As we figured out earlier in this discussion, by making Qt::partial_ordering
binary compatible with std::partial_ordering, we will allow the compiler to
optimize the code and avoid the conversions (specially if we use std::bit_cast).

Thanks,
Ivan


From: Development  on behalf of Thiago 
Macieira 
Sent: Tuesday, November 14, 2023 5:07 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Tuesday, 14 November 2023 04:17:18 PST Marc Mutz via Development wrote:
> It's dangerously close to q20, yes, but q20 types switch at compile-time
> between std and fall-back types, which means they cannot be used in the
> ABI (yes, I used qxp::function_ref in QTestLib, but that doesn't have a
> `using std::...`, yet, so we're still ok, and QTestLib doesn't have BC
> constraints).

Actually, how about we do exactly that: we DO NOT use them in the ABI and thus
we DO use std:: types when compiling in C++20 mode. We can only use them in
inline-only functions.

The ABI functions can return one of these other types:
  bool  (for equality comparisons)
  int  (for non-partial ordering)
  QPartialOrdering (for partial ordering)

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Thiago Macieira
On Tuesday, 14 November 2023 04:17:18 PST Marc Mutz via Development wrote:
> It's dangerously close to q20, yes, but q20 types switch at compile-time
> between std and fall-back types, which means they cannot be used in the
> ABI (yes, I used qxp::function_ref in QTestLib, but that doesn't have a
> `using std::...`, yet, so we're still ok, and QTestLib doesn't have BC
> constraints).

Actually, how about we do exactly that: we DO NOT use them in the ABI and thus 
we DO use std:: types when compiling in C++20 mode. We can only use them in 
inline-only functions.

The ABI functions can return one of these other types:
  bool  (for equality comparisons)
  int  (for non-partial ordering)
  QPartialOrdering (for partial ordering)

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Thiago Macieira
On Tuesday, 14 November 2023 04:17:18 PST Marc Mutz via Development wrote:
> It's dangerously close to q20, yes, but q20 types switch at compile-time
> between std and fall-back types, which means they cannot be used in the
> ABI (yes, I used qxp::function_ref in QTestLib, but that doesn't have a
> `using std::...`, yet, so we're still ok, and QTestLib doesn't have BC
> constraints).
> 
> The Qt::*ordering types, OTOH, are specifically _for_ use in the ABI.

This does mean those types won't be documented, right?

We forward to the C++ Standard Library documentation.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Marc Mutz via Development
On 14.11.23 11:54, Edward Welbourne wrote:
> Volker Hilsheimer (14 November 2023 10:00) wrote:
>> Adding Qt::snake_case interims that are BC with std, with conversion
>> from/to QPartialOrdering, is the right thing to do.
> 
> Perhaps namespace q20 would be a better place for them, given both the
> naming (snake-case, to match stl) and the plan ?

It's dangerously close to q20, yes, but q20 types switch at compile-time 
between std and fall-back types, which means they cannot be used in the 
ABI (yes, I used qxp::function_ref in QTestLib, but that doesn't have a 
`using std::...`, yet, so we're still ok, and QTestLib doesn't have BC 
constraints).

The Qt::*ordering types, OTOH, are specifically _for_ use in the ABI.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Volker Hilsheimer via Development
On 14 Nov 2023, at 10:00, Volker Hilsheimer via Development 
 wrote:
On 14 Nov 2023, at 09:40, Marc Mutz via Development 
 wrote:

On 14.11.23 09:31, Marc Mutz via Development wrote:
[...]
And then naming them Qt::partial_ordering is just consequent, because
users can reach ultimate SC by doing something like

#ifdef __cpp_lib_three_way_comparison
using std::partial_ordering;

#else
using Qt::partial_ordering;
#endif

~~~ use unqualified partial_ordering ~~~

This will also mean that in Qt 7 we can maintain 100% SC with Qt 6 by
simply saying

  namespace Qt {
  using partial_ordering = std::partial_ordering;
  using weak_ordering = std::weak_ordering;
  using strong_ordering = std::strong_ordering;
  }

Done.


I agree with Marc here.

It’s tempting to add some Qt::Ordering::Partial, but it only makes things 
harder in the not-so-long run. From C++ 23 on, we can expect 
std::partial/weak/strong_ordering to become as ubiquitous as “true” and 
“false”. We should not invent our own.

Adding Qt::snake_case interims that are BC with std, with conversion from/to 
QPartialOrdering, is the right thing to do.

On 14 Nov 2023, at 11:54, Edward Welbourne  wrote:
Adding Qt::snake_case interims that are BC with std, with conversion
from/to QPartialOrdering, is the right thing to do.

Perhaps namespace q20 would be a better place for them, given both the
naming (snake-case, to match stl) and the plan ?

and

On 14 Nov 2023, at 12:01, Tor Arne Vestbø  wrote:

The naming makes sense, given their purpose. But can we put them in a dedicated 
Qt::std_compat namespace? Or is that too late? That would make it clear these 
are not Qt proper types (living in the Qt namespace), but dedicated compat 
types/BC/SC vehicles


We have so far not used any q20/23/xp APIs in public Qt API, and those 
namespaces are not documented. The intention was for them to be used 
internally, and the qNN headers contain the “not part of the Qt API” warning. 
This doesn’t have to be set in stone, of course. Perhaps this is the exception 
that confirms the rule.

OTOH, if the only reason for not using Qt::snake_case is because of the 
snake_case, then it seems overly complicated to make that exception, or to 
introduce a new namespace. It’s going to be part of practically every 
value-type we have in Qt, which makes it a very very ubiquitous “exception”. We 
have QList::push_back and QList::const_iterator for compatibility with the 
standard. I don’t quite see why it would not be ok for Qt::*_ordering to exist 
as a proper Qt names. The only difference here is that we don’t want to 
introduce a Qt::CameCase equivalent, for the reasons given by Marc.

That they are short-lived as “independently defined entities” is an 
implementation detail. Qt::*_ordering will work throughout the Qt 6 life-time, 
also once they are just aliases to std::*_ordering; there won’t even be a real 
reason to remove them for Qt 7.


On 14 Nov 2023, at 11:54, Edward Welbourne  also wrote:
Speaking of q20, I notice its files live in corelib/global/; it occurs
to me that perhaps corelib/compat/ might be more natural (mainly because
it's the first place I looked for them).  They are, after all, a piece
of compatibility machinery, albeit between Qt and C++ rather than
between Qt versions (as such - of course, the Qt versions' change of C++
standard does make them indirectly also between Qt versions).

Eddy.

module/compat is about backward compatibility with older Qt versions, and in 
practice only includes the respective removed_api.cpp implementation file.

We include those qNN headers in public headers, and including something from 
“compat” in public headers seems wrong.

Volker


-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Tor Arne Vestbø via Development
The naming makes sense, given their purpose. But can we put them in a dedicated 
Qt::std_compat namespace? Or is that too late? That would make it clear these 
are not Qt proper types (living in the Qt namespace), but dedicated compat 
types/BC/SC vehicles .

Tor Arne

On 14 Nov 2023, at 10:00, Volker Hilsheimer via Development 
 wrote:



On 14 Nov 2023, at 09:40, Marc Mutz via Development 
 wrote:

On 14.11.23 09:31, Marc Mutz via Development wrote:
[...]
And then naming them Qt::partial_ordering is just consequent, because
users can reach ultimate SC by doing something like

#ifdef __cpp_lib_three_way_comparison
using std::partial_ordering;

#else
using Qt::partial_ordering;
#endif

~~~ use unqualified partial_ordering ~~~

This will also mean that in Qt 7 we can maintain 100% SC with Qt 6 by
simply saying

  namespace Qt {
  using partial_ordering = std::partial_ordering;
  using weak_ordering = std::weak_ordering;
  using strong_ordering = std::strong_ordering;
  }

Done.


I agree with Marc here.

It’s tempting to add some Qt::Ordering::Partial, but it only makes things 
harder in the not-so-long run. From C++ 23 on, we can expect 
std::partial/weak/strong_ordering to become as ubiquitous as “true” and 
“false”. We should not invent our own.

Adding Qt::snake_case interims that are BC with std, with conversion from/to 
QPartialOrdering, is the right thing to do.

Volker

--
Development mailing list
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


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Edward Welbourne via Development
Volker Hilsheimer (14 November 2023 10:00) wrote:
> Adding Qt::snake_case interims that are BC with std, with conversion
> from/to QPartialOrdering, is the right thing to do.

Perhaps namespace q20 would be a better place for them, given both the
naming (snake-case, to match stl) and the plan ?

Speaking of q20, I notice its files live in corelib/global/; it occurs
to me that perhaps corelib/compat/ might be more natural (mainly because
it's the first place I looked for them).  They are, after all, a piece
of compatibility machinery, albeit between Qt and C++ rather than
between Qt versions (as such - of course, the Qt versions' change of C++
standard does make them indirectly also between Qt versions).

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Volker Hilsheimer via Development


> On 14 Nov 2023, at 09:40, Marc Mutz via Development 
>  wrote:
> 
> On 14.11.23 09:31, Marc Mutz via Development wrote:
> [...]
>> And then naming them Qt::partial_ordering is just consequent, because
>> users can reach ultimate SC by doing something like
>> 
>>  #ifdef __cpp_lib_three_way_comparison
>>  using std::partial_ordering;
>>  
>>  #else
>>  using Qt::partial_ordering;
>>  #endif
>> 
>>  ~~~ use unqualified partial_ordering ~~~
> 
> This will also mean that in Qt 7 we can maintain 100% SC with Qt 6 by 
> simply saying
> 
>namespace Qt {
>using partial_ordering = std::partial_ordering;
>using weak_ordering = std::weak_ordering;
>using strong_ordering = std::strong_ordering;
>}
> 
> Done.


I agree with Marc here.

It’s tempting to add some Qt::Ordering::Partial, but it only makes things 
harder in the not-so-long run. From C++ 23 on, we can expect 
std::partial/weak/strong_ordering to become as ubiquitous as “true” and 
“false”. We should not invent our own.

Adding Qt::snake_case interims that are BC with std, with conversion from/to 
QPartialOrdering, is the right thing to do.

Volker

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Marc Mutz via Development
On 14.11.23 09:31, Marc Mutz via Development wrote:
[...]
> And then naming them Qt::partial_ordering is just consequent, because
> users can reach ultimate SC by doing something like
> 
>   #ifdef __cpp_lib_three_way_comparison
>   using std::partial_ordering;
>   
>   #else
>   using Qt::partial_ordering;
>   #endif
> 
>   ~~~ use unqualified partial_ordering ~~~

This will also mean that in Qt 7 we can maintain 100% SC with Qt 6 by 
simply saying

namespace Qt {
using partial_ordering = std::partial_ordering;
using weak_ordering = std::weak_ordering;
using strong_ordering = std::strong_ordering;
}

Done.

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Marc Mutz via Development
On 13.11.23 19:24, Thiago Macieira wrote:
[...]
> It could be done, but I just don't see the value.

I do.

> If we do it, please come up with proper Qt-style class names for it. No
> snake_case.

No. We don't _want_ these to be Qt-style classes. _You_ should not want 
them to be Qt-style classes. They're _not_ Qt classes, they're SC and BC 
vehicles to emulate the std classes as close as possible. We don't want 
to have to carry them around come Qt 7. You shouldn't want to have to 
carry them around come Qt 7.

So it must be ::less, not ::Less, and is_neq and not qIsNotEqual. Any 
epsilon of divergence to the std classes will cause users to 
accidentally depend on the difference. Hyrum's Law. So we need to 
minimize that difference as much as humanly possible.

And then naming them Qt::partial_ordering is just consequent, because 
users can reach ultimate SC by doing something like

 #ifdef __cpp_lib_three_way_comparison
 using std::partial_ordering;
 
 #else
 using Qt::partial_ordering;
 #endif

 ~~~ use unqualified partial_ordering ~~~

This is the best for our users. Any Qt-ification of these std copies 
will just increase the porting overhead for our users. In no universe 
would that be good for our users. We know where we need to go: no 
Qt::ordering classes, only std::ordering, and anything that distracts 
either our users or ourselves from that goal is counter-productive.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-14 Thread Marc Mutz via Development
On 13.11.23 19:25, Thiago Macieira wrote:
> On Monday, 13 November 2023 09:38:43 PST Ivan Solovev via Development wrote:
>> I really do not want to miss yet another FF.
> 
> Given that this is an API that is going to stay with us for at least a decade,
> I'd rather get it right than getting it soon.

We're discussing various tangential aspects for half a year now. At some 
point, all the cards are on the table and all that talking needs to come 
to some conclusion.

That point is now.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Thiago Macieira
On Monday, 13 November 2023 09:38:43 PST Ivan Solovev via Development wrote:
> I really do not want to miss yet another FF.

Given that this is an API that is going to stay with us for at least a decade, 
I'd rather get it right than getting it soon.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Thiago Macieira
On Monday, 13 November 2023 09:15:10 PST Marc Mutz via Development wrote:
> On 13.11.23 17:15, Thiago Macieira wrote:
> > On Monday, 13 November 2023 01:34:08 PST Ivan Solovev via Development 
wrote:
> > I don't think this minor thing is worth the hassle. It uglifies our API
> > for
> > little gain.
> 
> What, specifically, is ugly? That we have two Qt partial_ordering types?

Yes.

> Anyway, that's subjective. Objectively, it breaks the impasse between
> full efficiency in future-looking C++20 builds and Qt BC guarantees.

We're not losing anything either because the only case where this would be 
necessary is if we needed to return a std::partial_order result from a non-
inline function that is, in turn, calling the non-inline QMetaType and/or 
QVariant functions. We have zero of those today and aren't likely to get any 
of them, probably ever.

Some user code might, but I find it unlikely too. It could happen if the user 
decided to wrap a QVariant in a larger type that did have a three-way out-of-
line comparison function.

Everywhere else, the optimiser will do the right thing.

> Given that Qt 7.0 is many years away, I don't think it's too much to ask
> to go the extra mile and remove the overhead. We seem to agree how to do
> it technically, and it won't be on you to implement all this, but on
> Ivan and me. I think I speak for Ivan, too, if I say that we'd rather
> today than tomorrow see this stuff merged. The next FF is already
> approaching again.

It could be done, but I just don't see the value.

If we do it, please come up with proper Qt-style class names for it. No 
snake_case.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Ivan Solovev via Development
Marc wrote:
> I think I speak for Ivan, too, if I say that we'd rather
> today than tomorrow see this stuff merged. The next FF is already
> approaching again.

Right! This now seems to be the only thing blocking the whole
chain, and I think Marc's proposal solves all the issues.
I really do not want to miss yet another FF.

Best regards,
Ivan


From: Development  on behalf of Marc Mutz 
via Development 
Sent: Monday, November 13, 2023 6:15 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On 13.11.23 17:15, Thiago Macieira wrote:
> On Monday, 13 November 2023 01:34:08 PST Ivan Solovev via Development wrote:
>> Thiago wrote:
>>> The problem is that QPartialOrdering::Unordered has been in our ABI since
>>> 6.1 and we can't change that any more.
>>
>> Well, Marc already suggested a solution for this problem.
>> Let's just introduce Qt::{strong,weak,partial}_ordering and deprecate
>> QPartialOrdering in favor of the new types.
>>
>> We need to provide conversion between QPartialOrdering and
>> Qt::partial_ordering, but the new types can be fully BC with std.
>
> I don't think this minor thing is worth the hassle. It uglifies our API for
> little gain.

What, specifically, is ugly? That we have two Qt partial_ordering types?

Anyway, that's subjective. Objectively, it breaks the impasse between
full efficiency in future-looking C++20 builds and Qt BC guarantees.

Given that Qt 7.0 is many years away, I don't think it's too much to ask
to go the extra mile and remove the overhead. We seem to agree how to do
it technically, and it won't be on you to implement all this, but on
Ivan and me. I think I speak for Ivan, too, if I say that we'd rather
today than tomorrow see this stuff merged. The next FF is already
approaching again.

Thanks,
Marc

--
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

--
Development mailing list
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


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Marc Mutz via Development
On 13.11.23 17:15, Thiago Macieira wrote:
> On Monday, 13 November 2023 01:34:08 PST Ivan Solovev via Development wrote:
>> Thiago wrote:
>>> The problem is that QPartialOrdering::Unordered has been in our ABI since
>>> 6.1 and we can't change that any more.
>>
>> Well, Marc already suggested a solution for this problem.
>> Let's just introduce Qt::{strong,weak,partial}_ordering and deprecate
>> QPartialOrdering in favor of the new types.
>>
>> We need to provide conversion between QPartialOrdering and
>> Qt::partial_ordering, but the new types can be fully BC with std.
> 
> I don't think this minor thing is worth the hassle. It uglifies our API for
> little gain.

What, specifically, is ugly? That we have two Qt partial_ordering types?

Anyway, that's subjective. Objectively, it breaks the impasse between 
full efficiency in future-looking C++20 builds and Qt BC guarantees.

Given that Qt 7.0 is many years away, I don't think it's too much to ask 
to go the extra mile and remove the overhead. We seem to agree how to do 
it technically, and it won't be on you to implement all this, but on 
Ivan and me. I think I speak for Ivan, too, if I say that we'd rather 
today than tomorrow see this stuff merged. The next FF is already 
approaching again.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Thiago Macieira
On Monday, 13 November 2023 01:34:08 PST Ivan Solovev via Development wrote:
> Thiago wrote:
> > The problem is that QPartialOrdering::Unordered has been in our ABI since
> > 6.1 and we can't change that any more.
> 
> Well, Marc already suggested a solution for this problem.
> Let's just introduce Qt::{strong,weak,partial}_ordering and deprecate
> QPartialOrdering in favor of the new types.
> 
> We need to provide conversion between QPartialOrdering and
> Qt::partial_ordering, but the new types can be fully BC with std.

I don't think this minor thing is worth the hassle. It uglifies our API for 
little gain.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-13 Thread Ivan Solovev via Development
Thiago wrote:
> The problem is that QPartialOrdering::Unordered has been in our ABI since 6.1
> and we can't change that any more.

Well, Marc already suggested a solution for this problem.
Let's just introduce Qt::{strong,weak,partial}_ordering and deprecate 
QPartialOrdering
in favor of the new types.

We need to provide conversion between QPartialOrdering and 
Qt::partial_ordering, but
the new types can be fully BC with std.

See the details in https://bugreports.qt.io/browse/QTBUG-118913

Thanks,
Ivan


From: Development  on behalf of Thiago 
Macieira 
Sent: Friday, November 10, 2023 6:12 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Friday, 10 November 2023 00:11:11 PST Marc Mutz via Development wrote:
> On 09.11.23 16:28, Thiago Macieira wrote:
> > But if the symbols are globally visible (ELF visibility STV_DEFAULT)
>
> That counts as "exported", doesn't it?

Yes.

> Which leaves us with:
> - MSVC doesn't export anything by default; inline functions are,
> however, exported when the surrounding class is wholly exported
> - on all other platforms, all functions are by default "exported", but
> we emulate MSVC on those platforms by changing the default visibility to
> hidden, incl. for inline functions
>
> And my previous questions:
>
> - do our BC guarantees exist at all in the absence of
> `-fvisibility=hidden -fvisibility-inlines-hidden`?

Yes, we have to, because we don't control how the user's library is being
compiled.

> - does making the Qt and std::ordering types BC with each other not
> solve the problem in this case, too?

It does. We should really do that for Qt 7.0.

The problem is that QPartialOrdering::Unordered has been in our ABI since 6.1
and we can't change that any more.

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-10 Thread Thiago Macieira
On Friday, 10 November 2023 00:11:11 PST Marc Mutz via Development wrote:
> On 09.11.23 16:28, Thiago Macieira wrote:
> > But if the symbols are globally visible (ELF visibility STV_DEFAULT)
> 
> That counts as "exported", doesn't it?

Yes.

> Which leaves us with:
> - MSVC doesn't export anything by default; inline functions are,
> however, exported when the surrounding class is wholly exported
> - on all other platforms, all functions are by default "exported", but
> we emulate MSVC on those platforms by changing the default visibility to
> hidden, incl. for inline functions
> 
> And my previous questions:
> 
> - do our BC guarantees exist at all in the absence of
> `-fvisibility=hidden -fvisibility-inlines-hidden`?

Yes, we have to, because we don't control how the user's library is being 
compiled.

> - does making the Qt and std::ordering types BC with each other not
> solve the problem in this case, too?

It does. We should really do that for Qt 7.0.

The problem is that QPartialOrdering::Unordered has been in our ABI since 6.1 
and we can't change that any more.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-10 Thread Marc Mutz via Development
On 09.11.23 16:28, Thiago Macieira wrote:
> But if the symbols are globally visible (ELF visibility STV_DEFAULT)

That counts as "exported", doesn't it?

Which leaves us with:
- MSVC doesn't export anything by default; inline functions are, 
however, exported when the surrounding class is wholly exported
- on all other platforms, all functions are by default "exported", but 
we emulate MSVC on those platforms by changing the default visibility to 
hidden, incl. for inline functions

And my previous questions:

- do our BC guarantees exist at all in the absence of 
`-fvisibility=hidden -fvisibility-inlines-hidden`?
- does making the Qt and std::ordering types BC with each other not 
solve the problem in this case, too?

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-09 Thread Thiago Macieira
On Thursday, 9 November 2023 01:29:32 PST Ivan Solovev via Development wrote:
> Thiago wrote:
> > We can also just be evil and use bit_cast
> 
> Why is that evil? Reading about std::bit_cast, this can be an option, if we
> guarantee that sizeof(Qt::*_ordering) == sizeof(std::*_ordering).
> Which is, probably, already true.

Because the types in the libraries seem to be made so it's very difficult to 
get 
the actual values into and out of them. But bit_cast throws that away and 
allows us to see behind the scenes.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-09 Thread Thiago Macieira
On Wednesday, 8 November 2023 23:17:45 PST Marc Mutz via Development wrote:
> std::string is a type, but we're talking about function return types.
> Oranges and apples. Naturally the impact of the former is orders of
> magnitude larger than that of the latter.

std::string and std::__cxx11::string are different types, but someone changed 
which one got selected.

> > But why take the risk? The performance impact is minimal, because it only
> > applies to partial ordering, while the vast majority of types are fully
> > ordered.
> 
> Why do you say it only applies to partial ordering? Do we already match
> the values, other than that of std::partial_ordering::unordered?

Yes. It's always -1, 0 and 1 for all three Standard Libraries.

https://github.com/gcc-mirror/gcc/blob/releases/gcc-13.2.0/libstdc%2B%2B-v3/
libsupc%2B%2B/compare#L51-L53
https://github.com/llvm/llvm-project/blob/llvmorg-17.0.4/libcxx/include/
__compare/ordering.h#L25-L33
https://github.com/microsoft/STL/blob/main/stl/inc/compare#L43-L45

> I do note that you didn't attempt to poke holes into my documentation of
> my understanding of the "merge of inline functions from different
> libraries" issue.

You didn't ask anything.

> To TL;DR: it: I believe there is no way that an (application or) library
> can call another (dynamic) library's implementation of a non-exported inline
> function. It will always contain (and call) its own copy of the
> non-exported inline function.

That's only partially correct.

All libraries will contain out-of-line copies of any inline functions they 
didn't inline. This portion of your assertion was correct.

But if the symbols are globally visible (ELF visibility STV_DEFAULT), the 
dynamic linker will resolve all calls to the same symbol in one of the 
libraries, whichever one got loaded first by the depth-first library search and 
load order.

> Independent of the resolution of the C++20 comparison return types, I
> think it's vital to come to a common understanding of whether there is
> an actual issue with non-exported inline functions in ABIs (and then
> document it in the KDE BC wiki).

The documentation there is correct: you can change inline functions and 
uninline them so long as the old copy can keep on being called. That says 
nothing about changing the function's return type or the layout of the type it 
does return.

But yes we should add to it.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-09 Thread Ivan Solovev via Development
Marc wrote:
> Why do you say it only applies to partial ordering? Do we already match
> the values, other than that of std::partial_ordering::unordered?

Yes, we do.

Thiago wrote:
> We can also just be evil and use bit_cast

Why is that evil? Reading about std::bit_cast, this can be an option, if we
guarantee that sizeof(Qt::*_ordering) == sizeof(std::*_ordering).
Which is, probably, already true.

Thanks,
Ivan


From: Development  on behalf of Marc Mutz 
via Development 
Sent: Thursday, November 9, 2023 8:17 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On 08.11.23 16:46, Thiago Macieira wrote:
> On Wednesday, 8 November 2023 00:38:32 PST Marc Mutz via Development wrote:
>> Let's not mix up topics here...
>>
>> 1/ We're not responsible for the ABI of third-party libraries. As long as
>> we document that the return type of a non-exported inline functions
>> changes, then it's SEP if someone else writes code that ties their ABI
>> to the result type of such functions.
>
> Fair, but we are responsible if we make it difficult for them to do this, or
> make it trivial for them to have the problem without knowing that they have
> it. That was the issue with std::string in libstdc++: it kept libstdc++ BC,
> but broke everyone downstream of it.

std::string is a type, but we're talking about function return types.
Oranges and apples. Naturally the impact of the former is orders of
magnitude larger than that of the latter.

>> That leaves 2/ the mythical "merge of inline functions from different
>> libraries" and 3/ "mixing of C++ versions within the same executable"
>> situations.
>>
>> I agree that the latter is a problem; I stated as much in my previous
>> email, and gave (1) and (3) as solutions.
>>
>> But I still don't see how the former is a problem, or, if it is, why (3)
>> (BC between {std,Qt}::_ordering) doesn't fix it, too.
>
> I think it's acceptable for us to change the return type of a function so long
> as it's getting a new mangling. That means it can apply to any regular
> function, but not operators. Then again, all of the latter return bool except
> for operator<=> so there's no problem there either.
 >
> But why take the risk? The performance impact is minimal, because it only
> applies to partial ordering, while the vast majority of types are fully
> ordered.

Why do you say it only applies to partial ordering? Do we already match
the values, other than that of std::partial_ordering::unordered?

> The impact of QAnyStringView in any API is greater.

Unrelated.


I do note that you didn't attempt to poke holes into my documentation of
my understanding of the "merge of inline functions from different
libraries" issue.

To TL;DR: it: I believe there is no way that an (application or) library
can call another (dynamic) library's implementation of a non-exported inline
function. It will always contain (and call) its own copy of the
non-exported inline function.

Independent of the resolution of the C++20 comparison return types, I
think it's vital to come to a common understanding of whether there is
an actual issue with non-exported inline functions in ABIs (and then
document it in the KDE BC wiki).

Thanks,
Marc

--
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

--
Development mailing list
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


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-08 Thread Marc Mutz via Development
On 08.11.23 16:46, Thiago Macieira wrote:
> On Wednesday, 8 November 2023 00:38:32 PST Marc Mutz via Development wrote:
>> Let's not mix up topics here...
>>
>> 1/ We're not responsible for the ABI of third-party libraries. As long as
>> we document that the return type of a non-exported inline functions
>> changes, then it's SEP if someone else writes code that ties their ABI
>> to the result type of such functions.
> 
> Fair, but we are responsible if we make it difficult for them to do this, or
> make it trivial for them to have the problem without knowing that they have
> it. That was the issue with std::string in libstdc++: it kept libstdc++ BC,
> but broke everyone downstream of it.

std::string is a type, but we're talking about function return types. 
Oranges and apples. Naturally the impact of the former is orders of 
magnitude larger than that of the latter.

>> That leaves 2/ the mythical "merge of inline functions from different
>> libraries" and 3/ "mixing of C++ versions within the same executable"
>> situations.
>>
>> I agree that the latter is a problem; I stated as much in my previous
>> email, and gave (1) and (3) as solutions.
>>
>> But I still don't see how the former is a problem, or, if it is, why (3)
>> (BC between {std,Qt}::_ordering) doesn't fix it, too.
> 
> I think it's acceptable for us to change the return type of a function so long
> as it's getting a new mangling. That means it can apply to any regular
> function, but not operators. Then again, all of the latter return bool except
> for operator<=> so there's no problem there either.
 >
> But why take the risk? The performance impact is minimal, because it only
> applies to partial ordering, while the vast majority of types are fully
> ordered.

Why do you say it only applies to partial ordering? Do we already match 
the values, other than that of std::partial_ordering::unordered?

> The impact of QAnyStringView in any API is greater.

Unrelated.


I do note that you didn't attempt to poke holes into my documentation of 
my understanding of the "merge of inline functions from different 
libraries" issue.

To TL;DR: it: I believe there is no way that an (application or) library 
can call another (dynamic) library's implementation of a non-exported inline 
function. It will always contain (and call) its own copy of the 
non-exported inline function.

Independent of the resolution of the C++20 comparison return types, I 
think it's vital to come to a common understanding of whether there is 
an actual issue with non-exported inline functions in ABIs (and then 
document it in the KDE BC wiki).

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-08 Thread Thiago Macieira
On Wednesday, 8 November 2023 10:05:38 PST Ivan Solovev via Development wrote:
> > I think it's acceptable for us to change the return type of a function so
> > long as it's getting a new mangling.
> 
> Well, it would be easily achievable for the template methods, but not for
> the inline hidden friend helper methods.
> As immediate solution that comes to my mind is to add a third argument to
> these methods when compiled in C++20 mode. And we could probably use
> yet another macro for that. But this will just overcomplicate the things, so
> I'm not a big fan of this idea.

Neither am I.

If we do this, the third, dummy, disambiguating parameter should simply be the 
return type itself. It's the clearest solution and makes macro definition 
simpler.

> So, you say that the compiler is smart enough to optimize away conversions
> like `std::strong_ordering -> QStrongOrdering -> std::strong_ordering`
> because the underlying integral values are the same?

Yes. Since everything is idempotent, it should just do nothing.

In practice, it looks like one of the conversions is getting clamped:
https://gcc.godbolt.org/z/n7ohc9Wo4

It might be possible to massage the code in such a way that the compiler 
realises that it is always idempotent. I haven't managed yet. We can also just 
be evil and use bit_cast:
https://gcc.godbolt.org/z/e5zefKevP

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-08 Thread Ivan Solovev via Development
> I think it's acceptable for us to change the return type of a function so long
> as it's getting a new mangling.

Well, it would be easily achievable for the template methods, but not for the
inline hidden friend helper methods.
As immediate solution that comes to my mind is to add a third argument to
these methods when compiled in C++20 mode. And we could probably use
yet another macro for that. But this will just overcomplicate the things, so
I'm not a big fan of this idea.

> But why take the risk? The performance impact is minimal, because it only
> applies to partial ordering, while the vast majority of types are fully
> ordered.

So, you say that the compiler is smart enough to optimize away conversions like
`std::strong_ordering -> QStrongOrdering -> std::strong_ordering`
because the underlying integral values are the same?

I did some experiments in compiler explorer, and it seems that gcc and clang
generate similar assembly code with and without conversions.
MSVC is a bit special here, however.
See my experiments here:https://godbolt.org/z/G8Ks9v9Ks

In this case we could probably apply Marc's proposal #3 (making std::* and Qt::*
types binary compatible), and just stick to the Qt::* types in the API?

Thanks,
Ivan


From: Development  on behalf of Thiago 
Macieira 
Sent: Wednesday, November 8, 2023 4:46 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 8 November 2023 00:38:32 PST Marc Mutz via Development wrote:
> Let's not mix up topics here...
>
> 1/ We're not responsible for the ABI of third-party libraries. As long as
> we document that the return type of a non-exported inline functions
> changes, then it's SEP if someone else writes code that ties their ABI
> to the result type of such functions.

Fair, but we are responsible if we make it difficult for them to do this, or
make it trivial for them to have the problem without knowing that they have
it. That was the issue with std::string in libstdc++: it kept libstdc++ BC,
but broke everyone downstream of it.

> That leaves 2/ the mythical "merge of inline functions from different
> libraries" and 3/ "mixing of C++ versions within the same executable"
> situations.
>
> I agree that the latter is a problem; I stated as much in my previous
> email, and gave (1) and (3) as solutions.
>
> But I still don't see how the former is a problem, or, if it is, why (3)
> (BC between {std,Qt}::_ordering) doesn't fix it, too.

I think it's acceptable for us to change the return type of a function so long
as it's getting a new mangling. That means it can apply to any regular
function, but not operators. Then again, all of the latter return bool except
for operator<=> so there's no problem there either.

But why take the risk? The performance impact is minimal, because it only
applies to partial ordering, while the vast majority of types are fully
ordered. The impact of QAnyStringView in any API is greater.

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-08 Thread Thiago Macieira
On Wednesday, 8 November 2023 00:38:32 PST Marc Mutz via Development wrote:
> Let's not mix up topics here...
> 
> 1/ We're not responsible for the ABI of third-party libraries. As long as
> we document that the return type of a non-exported inline functions
> changes, then it's SEP if someone else writes code that ties their ABI
> to the result type of such functions.

Fair, but we are responsible if we make it difficult for them to do this, or 
make it trivial for them to have the problem without knowing that they have 
it. That was the issue with std::string in libstdc++: it kept libstdc++ BC, 
but broke everyone downstream of it.

> That leaves 2/ the mythical "merge of inline functions from different
> libraries" and 3/ "mixing of C++ versions within the same executable"
> situations.
> 
> I agree that the latter is a problem; I stated as much in my previous
> email, and gave (1) and (3) as solutions.
> 
> But I still don't see how the former is a problem, or, if it is, why (3)
> (BC between {std,Qt}::_ordering) doesn't fix it, too.

I think it's acceptable for us to change the return type of a function so long 
as it's getting a new mangling. That means it can apply to any regular 
function, but not operators. Then again, all of the latter return bool except 
for operator<=> so there's no problem there either.

But why take the risk? The performance impact is minimal, because it only 
applies to partial ordering, while the vast majority of types are fully 
ordered. The impact of QAnyStringView in any API is greater.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-08 Thread Marc Mutz via Development
Let's not mix up topics here...

1/ We're not responsible for the ABI of third-party libraries. As long as 
we document that the return type of a non-exported inline functions 
changes, then it's SEP if someone else writes code that ties their ABI 
to the result type of such functions.

We're only responsible for our own ABIs. And _we_ know not to export 
functions that can change return type.

That leaves 2/ the mythical "merge of inline functions from different 
libraries" and 3/ "mixing of C++ versions within the same executable" 
situations.

I agree that the latter is a problem; I stated as much in my previous 
email, and gave (1) and (3) as solutions.

But I still don't see how the former is a problem, or, if it is, why (3)
(BC between {std,Qt}::_ordering) doesn't fix it, too.

On 08.11.23 01:16, Thiago Macieira wrote:
> On Tuesday, 7 November 2023 13:34:04 PST Marc Mutz via Development wrote:
>>> Yes. Remember that "one binary" is the process as loaded into memory,
>>> including all the libraries. Depending on compilation modes, inline
>>> functions may be merged from multiple independent libraries at runtime.
>>
>> Sorry, but [citation needed]. This goes against _everything_ I know and,
>> more importantly, everything we've been doing the last decades, incl.
>> your own https://codereview.qt-project.org/c/qt/qtbase/+/389682
> 
> Any debug build that isn't using -fvisibility-inlines-hidden.

Does this apply only to inline methods of exported classes, or to any 
inline function at namespace scope, too? Anyway, I thought that Qt is 
always compiled with -fvisibility-inlines-hidden? Do our BC guarantees 
even apply if they're not? E.g. how can we remove an inline function and 
have it be BC? In the specific case of QVersionNumber::size(): the 
mangling changed on MSVC, so we removed the function and replaced it 
with another one. That was ok, though, since QVN is _not_ exported, so 
each user contains its own copy of the function.

Case in point: We didn't add a new overload of resize() 
https://codereview.qt-project.org/c/qt/qtbase/+/389682/5/src/corelib/tools/qversionnumber.h#175
 
to keep old source working, we _replaced_ the function. If what you say 
is true, then that would be BiC, because existing users of the function 
would not find the new function (with a different mangled name). This is 
safe precisely because non-exported inline functions are _not_ magically 
called from other libraries. This is a cornerstone of our API evolution.

> Or release
> builds for any inline function that didn't get inlined.

[citation needed]

AFAIK, if a non-exported inline function isn't inlined, then each TU 
contains an out-of-line copy of the function and the (static) linker 
will de-duplicate them all into a single one. That's per executable 
("cmake target", for dynamic linking), and means that each executable 
contains its own independent copy of the code.

Call me daft, but I still don't see it.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Thiago Macieira
On Tuesday, 7 November 2023 13:34:04 PST Marc Mutz via Development wrote:
> > Yes. Remember that "one binary" is the process as loaded into memory,
> > including all the libraries. Depending on compilation modes, inline
> > functions may be merged from multiple independent libraries at runtime.
> 
> Sorry, but [citation needed]. This goes against _everything_ I know and,
> more importantly, everything we've been doing the last decades, incl.
> your own https://codereview.qt-project.org/c/qt/qtbase/+/389682

Any debug build that isn't using -fvisibility-inlines-hidden. Or release 
builds for any inline function that didn't get inlined.

Changing of int to qsizetype or qint64 "works" so long as the data actually 
fits the int, which for QVersionNumber is 100% of the cases (I'm not even going 
to say it's "indistinguishable from 100%" because *no one* uses 2.1 billion 
version segments). This problem also only applies to QVersionNumber::size() 
and QVersionNumber::SegmentStorage::size(), because only those two would have 
the same mangling. All the other functions changed by that commit are new 
overloads.

Trying to do the same for QTimer[1] is similar, ignoring the Q_PROPERTY / 
QProperty issues. Because it's exported, we'd need to add a new overload, but 
that just moves the problem one step further. Imagine:

  auto intervalFor(QTimer ) { return t.interval(); }

If recompiled, this code would start returning qint64 instead of int, but 
would have the same mangling under the IA-64 ABI, which is bad but mostly 
acceptable because it is data-compatible for any timer of less than 24.85 days 
(which is ALL of them today).

This above is inline so it goes back to the original problem of non-inlined 
inline functions. In the case of our comparison types, someone may see that it 
returns auto and decides to write an out-of-line version as:

class MYLIB_EXPORT  Foo
{
static decltype(Qt::compareThreeWay(0, 0)) compareThreeWay(Foo, Foo);
};

We'd have to document for them not to do this.

This has also just made me realise a different problem: with MSVC, the mangling 
of the function would change. And it's easy to get that problem just by 
exporting one's class, because it always exports inline functions and calls 
that out-of-line copy imported inline function for anything non-trivial:

class MYLIB_EXPORT  Foo
{
int x;
public:
auto compare(Foo a, Foo b) { return Qt::compareThreeWay(a.x, b.x); }

};

So if this user's library is recompiled with a different setting, the ABI 
changes. If the user's user's code mismatches the library, it will fail to 
link.

Therefore, "Almost Never Auto" applies and especially so for return types 
(when used for deducing a type, not for syntactic brevity).

[1] https://codereview.qt-project.org/c/qt/qtbase/+/491119

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Marc Mutz via Development
On 07.11.23 20:12, Thiago Macieira wrote:
> On Tuesday, 7 November 2023 06:28:51 PST Ivan Solovev via Development wrote:
[...]
>> The main reason to use `auto` is that it will allow us to avoid unnecessary
>> `std::*_ordering -> Q*Ordering -> std::*_ordering` conversions in the C++20
>> case, which will hopefully be the common case going forward.
>>
>> The main argument agains it is the possible ODR violation when mixing C++17
>> and C++20 in one binary.
>>
>> So, my question is - shoud we support mixing C++17 and C++20 in one binary?
> 
> Yes. Remember that "one binary" is the process as loaded into memory,
> including all the libraries. Depending on compilation modes, inline functions
> may be merged from multiple independent libraries at runtime.

Sorry, but [citation needed]. This goes against _everything_ I know and, 
more importantly, everything we've been doing the last decades, incl. 
your own https://codereview.qt-project.org/c/qt/qtbase/+/389682

> So don't violate ODR.
> 
> At worst, you can make them overload each other by having different 
> parameters.
> So the Qt functions can switch between the two return type families. But you
> can't overload operators, so operators must return one family only.



-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Thiago Macieira
On Tuesday, 7 November 2023 09:07:10 PST Marc Mutz via Development wrote:
> To be clear: This is not about Qt compiled with C++17 used in projects
> compiled with C++20. This is about one .cpp file being compiled with
> C++17 and another .cpp file from, broadly speaking, the same cmake
> target, in C++20 (static builds are different; there, the whole
> application incl. all "statically-linked libraries", is one executable).

No, it's not. See my reply. Your answer still applies, just that it gets 
bigger so:

> 1. Ban mixing different C++ versions in the same executable (= cmake
> target).
> 
> This is probably the safest. If we allowed this instead, we'd need to
> review all of our APIs to see whether we have a similar issue already.

You must remove "cmake target" portion. This applies to the executable as 
loaded into memory.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Thiago Macieira
On Tuesday, 7 November 2023 06:28:51 PST Ivan Solovev via Development wrote:
> Hi,
> 
> I'd like to discuss one more topic regarding the C++20 comparison.
> 
> Can we allow an `auto` return type in helper functions and the three-way
> comparison implementation for the built-in types?

Answering the question as asked: yes. 

So long it always resolves to the same thing.

> The idea is that these methods can return `Q*Ordering` types in C++17 mode,
> and `std::*_ordering` types in C++20 mode.

No. They must return the same thing. Choose one and stick to it until Qt 7.

> The main reason to use `auto` is that it will allow us to avoid unnecessary
> `std::*_ordering -> Q*Ordering -> std::*_ordering` conversions in the C++20
> case, which will hopefully be the common case going forward.
> 
> The main argument agains it is the possible ODR violation when mixing C++17
> and C++20 in one binary.
> 
> So, my question is - shoud we support mixing C++17 and C++20 in one binary?

Yes. Remember that "one binary" is the process as loaded into memory, 
including all the libraries. Depending on compilation modes, inline functions 
may be merged from multiple independent libraries at runtime.

So don't violate ODR.

At worst, you can make them overload each other by having different parameters. 
So the Qt functions can switch between the two return type families. But you 
can't overload operators, so operators must return one family only.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Marc Mutz via Development
On 07.11.23 15:28, Ivan Solovev via Development wrote:
> 
> So, my question is - shoud we support mixing C++17 and C++20 in one binary?

To be clear: This is not about Qt compiled with C++17 used in projects 
compiled with C++20. This is about one .cpp file being compiled with 
C++17 and another .cpp file from, broadly speaking, the same cmake 
target, in C++20 (static builds are different; there, the whole 
application incl. all "statically-linked libraries", is one executable).

What will happen is that the first TU is using a Q*Ordering return type 
and the second TU is using the std::*_order return type. The linker will 
them de-duplicate these per-TU inline function bodies and pick one of 
them. Lets say, for the sake of argument, the C++17 one. Since the two 
sets of ordering types are not binary compatible, and equivalent states 
have different numerical values, the result of the call to the function 
in the C++20 TU will be misinterpreted when it comes from the C++17 
function. Of course, the whole thing is UB, so we may not even get so 
far as a possible misinterpretation.

There are several ways to solve this:

1. Ban mixing different C++ versions in the same executable (= cmake 
target).

This is probably the safest. If we allowed this instead, we'd need to 
review all of our APIs to see whether we have a similar issue already.

2. always use only the Q*Ordering types.

Esp. since the numerical values of std::*_ordering and Q*Ordering don't 
match, this will inject value-mapping code in future-proof idiomatic 
C++20 code like

switch (lhs <=> rhs) {
case std::strong_order::less: ~~~;
~~~;
}

I would very much like to avoid that overhead.

3. make the Q*Ordering types binary compatible with the std ones.

If they're binary compatible, then while technically UB (ODR violation) 
the situation would be very much like any other change to inline API.

There are two issues here: First, different std libs have different 
values for the different states, so we'd need to #ifdef our own enum to 
what the currently-used stdlib is using. Second, QPartialOrdering was 
released independent of the C++20 comparison work, in Qt 6.0. So we 
would need to dissociate the C++20 comparison stuff from it and rename 
the existing 6.7 Q*Ordering types to, say, Qt:*_ordering, to start with 
a clean slate.

My opinion:
- 1 is simplest, but we don't control how users compile our APIs, so 
someone may still trigger this
- 3 is cleanest, therefore preferred: the complexity is on us, but the 
resulting code is as efficient as can be, regardless of C++17 or C++20. 
This is how it should be in C++.
- I don't like 2. It has it all backwards.


Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-11-07 Thread Ivan Solovev via Development
Hi,

I'd like to discuss one more topic regarding the C++20 comparison.

Can we allow an `auto` return type in helper functions and the three-way
comparison implementation for the built-in types?

The idea is that these methods can return `Q*Ordering` types in C++17 mode, and
`std::*_ordering` types in C++20 mode.

The question was raised and discussed here:
https://codereview.qt-project.org/c/qt/qtbase/+/478199/comment/bbab752c_520dc684/

Now we have two controversial opinions.

The main reason to use `auto` is that it will allow us to avoid unnecessary
`std::*_ordering -> Q*Ordering -> std::*_ordering` conversions in the C++20
case, which will hopefully be the common case going forward.

The main argument agains it is the possible ODR violation when mixing C++17
and C++20 in one binary.

So, my question is - shoud we support mixing C++17 and C++20 in one binary?

Before continuing with the patches, I'd like to hear more opinions.

Thanks,
Ivan


From: Ivan Solovev 
Sent: Wednesday, October 4, 2023 11:15 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

So, let me give another update.

The chaing ending in https://codereview.qt-project.org/c/qt/qtbase/+/508464
passed a full pre-check in the CI.
It implements the macros in terms of helper functions ``comparesEqual()``
and ``compareThreeWay()``.
The macros are documented as internal for now.

It also provides ``qCompareThreeWay()`` as a public API for three-way
comparison.

The chain also contains examples of applying the new macros to some of the Qt
classes: QTime, QDate, QDateTime, QTimeZone, and qfloat16.

I think, Marc also started migrating more Qt classes to the new macros.

We also have a draft of a QUIP which describes how to apply the new macros
to the Qt classes: https://codereview.qt-project.org/c/meta/quips/+/490932

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Edward Welbourne 
Sent: Tuesday, September 26, 2023 4:31 PM
To: development@qt-project.org ; Ivan Solovev 

Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

Thiago wrote:
>> See my other email: the (1) is not discoverable, teachable, or
>> particularly understandable by average C++ developers. It is not a
>> good corner of C++.

Ivan Solovev (21 September 2023 11:10) replied:
> As you correctly pointed out, most of the developers will just use
> public operator==(), and, come C++20, operator<=>().
>
> But I'd say that if someone wants to implement three-way comparison
> for their classes in C++17, then a bit better understanding of the
> language features is a reasonable expectation.

You're not thinking of all the different users of code.  The author of a
class using Qt, that opts to use our mechanism for comparisons, can
indeed be expected to understand the fancy new language features, around
which that mechanism is built.

However, the client of that code, who just wants to compare two things,
is a separate player in the game; you're also expecting them to have
that level of sophistication.  That's more of a stretch: they're just
trying to coax their template into coping with one of its parameters
being this class that someone using Qt has exposed to them in a library
they're using.  They may not even be using Qt themselves, merely
publishing a helper template that someone else is trying to use in
conjunction with some classes written using Qt.  We don't want them to
throw up their hands and tell the users of their template they don't
support use of Qt classes with their templates because "Qt does things
weirdly" (as far as they're concerned).

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-10-04 Thread Ivan Solovev via Development
So, let me give another update.

The chaing ending in https://codereview.qt-project.org/c/qt/qtbase/+/508464
passed a full pre-check in the CI.
It implements the macros in terms of helper functions ``comparesEqual()``
and ``compareThreeWay()``.
The macros are documented as internal for now.

It also provides ``qCompareThreeWay()`` as a public API for three-way
comparison.

The chain also contains examples of applying the new macros to some of the Qt
classes: QTime, QDate, QDateTime, QTimeZone, and qfloat16.

I think, Marc also started migrating more Qt classes to the new macros.

We also have a draft of a QUIP which describes how to apply the new macros
to the Qt classes: https://codereview.qt-project.org/c/meta/quips/+/490932

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Edward Welbourne 
Sent: Tuesday, September 26, 2023 4:31 PM
To: development@qt-project.org ; Ivan Solovev 

Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

Thiago wrote:
>> See my other email: the (1) is not discoverable, teachable, or
>> particularly understandable by average C++ developers. It is not a
>> good corner of C++.

Ivan Solovev (21 September 2023 11:10) replied:
> As you correctly pointed out, most of the developers will just use
> public operator==(), and, come C++20, operator<=>().
>
> But I'd say that if someone wants to implement three-way comparison
> for their classes in C++17, then a bit better understanding of the
> language features is a reasonable expectation.

You're not thinking of all the different users of code.  The author of a
class using Qt, that opts to use our mechanism for comparisons, can
indeed be expected to understand the fancy new language features, around
which that mechanism is built.

However, the client of that code, who just wants to compare two things,
is a separate player in the game; you're also expecting them to have
that level of sophistication.  That's more of a stretch: they're just
trying to coax their template into coping with one of its parameters
being this class that someone using Qt has exposed to them in a library
they're using.  They may not even be using Qt themselves, merely
publishing a helper template that someone else is trying to use in
conjunction with some classes written using Qt.  We don't want them to
throw up their hands and tell the users of their template they don't
support use of Qt classes with their templates because "Qt does things
weirdly" (as far as they're concerned).

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-26 Thread Edward Welbourne via Development
Thiago wrote:
>> See my other email: the (1) is not discoverable, teachable, or
>> particularly understandable by average C++ developers. It is not a
>> good corner of C++.

Ivan Solovev (21 September 2023 11:10) replied:
> As you correctly pointed out, most of the developers will just use
> public operator==(), and, come C++20, operator<=>().
>
> But I'd say that if someone wants to implement three-way comparison
> for their classes in C++17, then a bit better understanding of the
> language features is a reasonable expectation.

You're not thinking of all the different users of code.  The author of a
class using Qt, that opts to use our mechanism for comparisons, can
indeed be expected to understand the fancy new language features, around
which that mechanism is built.

However, the client of that code, who just wants to compare two things,
is a separate player in the game; you're also expecting them to have
that level of sophistication.  That's more of a stretch: they're just
trying to coax their template into coping with one of its parameters
being this class that someone using Qt has exposed to them in a library
they're using.  They may not even be using Qt themselves, merely
publishing a helper template that someone else is trying to use in
conjunction with some classes written using Qt.  We don't want them to
throw up their hands and tell the users of their template they don't
support use of Qt classes with their templates because "Qt does things
weirdly" (as far as they're concerned).

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-22 Thread Thiago Macieira
On Friday, 22 September 2023 05:46:27 PDT Marc Mutz via Development wrote:
> Where do you draw the line between "Allowing class developers to
> implement the three-way comparison such that Qt can make use of it is
> fine." and "Providing an API for three-way comparison in C++17 does not
> need to happen."?

At our maintenance cost. If it costs us more to create something they can use, 
then it needs to be long-term justified. A short-term requirement for people 
who can't upgrade requires a very high justification.

> How is said Qt class author supposed to implement his cmp(lhs, rhs) if
> there is no "API" for doing this on his data members? As a concrete
> example, how is the author of a `struct QFoo { int; QString; }` supposed
> to implement his cmp() if all he gets is op<=>, a C++20-only API?

How they implement their three-way comparison for their internals is their 
problem. So long as they somehow provide the method that our macros require, 
they can use the macros.

But we don't have to help them there. We can't help them with types from 
third-party libraries we don't know about in the first place; they have to 
implement the three-way comparison themselves anyway. Having a (4) that allows 
them to compare Qt types and compose solves 99% of the problems. For the rest, 
they can figure out on their own or just use the spaceship operator.

And this is even assuming that we document the macros for public use in the 
first place.

> I don't see how we can manage without an API for doing three-way
> comparisons in C++17.
> 
> We can try without (4), but (1)-(3) must needs be "semi-public" API (not
> in _p.h's).

I'm ok with semi-public. That means I can change them or remove them.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-22 Thread Marc Mutz via Development
On 21.09.23 18:02, Thiago Macieira wrote:
> On Thursday, 21 September 2023 02:10:22 PDT Ivan Solovev via Development
> wrote:
>> But I'd say that if someone wants to implement three-way comparison for
>> their classes in C++17, then a bit better understanding of the language
>> features is a reasonable expectation.
> 
> Allowing class developers to implement the three-way comparison such that Qt
> can make use of it is fine. That's basically allowing them to use the same
> technique we will be using to make our classes three-way comparable.
> 
> Providing an API for three-way comparison in C++17 does not need to happen.

Where do you draw the line between "Allowing class developers to 
implement the three-way comparison such that Qt can make use of it is 
fine." and "Providing an API for three-way comparison in C++17 does not 
need to happen."?

A Qt class author is supposed to implement a (however named) eq(lhs, 
rhs) and cmp(lhs, rhs) function. These functions are then translated into

- in C++17:
   - by our macros:
 - ==, !=
 - <, >, <=, >=
 - ==, != (reversed)
 - <, >, <=, >= (reversed)
- in C++20:
   - by our macros:
 - ==
 - <=>
   - from these, by the compiler:
 - !=
 - ==, != (reversed)
 - <, >, <=, >=
 - <, >, <=, >= (reversed)

How is said Qt class author supposed to implement his cmp(lhs, rhs) if 
there is no "API" for doing this on his data members? As a concrete 
example, how is the author of a `struct QFoo { int; QString; }` supposed 
to implement his cmp() if all he gets is op<=>, a C++20-only API?

I don't see how we can manage without an API for doing three-way 
comparisons in C++17.

We can try without (4), but (1)-(3) must needs be "semi-public" API (not 
in _p.h's).

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-21 Thread Thiago Macieira
On Thursday, 21 September 2023 02:10:22 PDT Ivan Solovev via Development 
wrote:
> But I'd say that if someone wants to implement three-way comparison for
> their classes in C++17, then a bit better understanding of the language
> features is a reasonable expectation.

Allowing class developers to implement the three-way comparison such that Qt 
can make use of it is fine. That's basically allowing them to use the same 
technique we will be using to make our classes three-way comparable.

Providing an API for three-way comparison in C++17 does not need to happen. 
People can upgrade to C++20 or complain to their vendors. We are talking about 
adding this to a Qt release to happen in 2024, nearly 4 years after the C++ 
edition was published.

I won't oppose it if it is simple, without imposing undue constraints. But it 
need not be part of the initial design.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-21 Thread Ivan Solovev via Development
I drafted a QUIP that describes how to apply C++20 comparison to Qt classes:

https://codereview.qt-project.org/c/meta/quips/+/490932

It intentionally does not mention `qCompareThreeWay()` and `qComparesEqual()`,
because these public APIs are not required for the internal implementation.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Ivan 
Solovev via Development 
Sent: Thursday, September 21, 2023 11:10 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

> See my other email: the (1) is not discoverable, teachable, or particularly
> understandable by average C++ developers. It is not a good corner of C++.

As you correctly pointed out, most of the developers will just use public
operator==(), and, come C++20, operator<=>().

But I'd say that if someone wants to implement three-way comparison for their
classes in C++17, then a bit better understanding of the language features is
a reasonable expectation.

At the same time, if we use Volker's suggestion and go with `compareThreeWay`
and `comparesEqual` as the names for (1), I do not see any problems in
implementing `qCompareThreeWay` as (4).

Later we can also add `qComparesEqual` for consistency and even provide
3-arg overloads for string-like types, like Marc suggests.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Ivan 
Solovev via Development 
Sent: Thursday, September 21, 2023 10:43 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

> I have just rebased the chain on top of the latest dev and fixed the issue
> with qfloat16 and -Wfloat-equal.
> Now it builds fine for me locally on Linux with GCC. Started a full pre-check
> in the CI to test other configurations.
> I'll keep an eye on the pre-check results and try to fix any other errors,
> if they occur.

The qfloat16 patch does have some issues, because MSVC behaves differently from
other compilers. That's something that needs a deeper investigation.

Meanwhile, the full CI pre-check for the previous patch in the chain has
completed successfully.
So, you can use https://codereview.qt-project.org/c/qt/qtbase/+/479395 to
test the approach.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Thiago 
Macieira 
Sent: Thursday, September 21, 2023 2:22 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 20 September 2023 02:53:37 PDT Volker Hilsheimer via Development
wrote:
> If we can have (1), i.e.
>
> using Qt::equals;
> equals(a, b);
>
> why do we need qEquals?

See my other email: the (1) is not discoverable, teachable, or particularly
understandable by average C++ developers. It is not a good corner of C++.

(4) (the convenience function) is what users expect. Except that we don't need
it to be called qEquals, because we have an even better name for it:

operator==

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-21 Thread Ivan Solovev via Development
> See my other email: the (1) is not discoverable, teachable, or particularly
> understandable by average C++ developers. It is not a good corner of C++.

As you correctly pointed out, most of the developers will just use public
operator==(), and, come C++20, operator<=>().

But I'd say that if someone wants to implement three-way comparison for their
classes in C++17, then a bit better understanding of the language features is
a reasonable expectation.

At the same time, if we use Volker's suggestion and go with `compareThreeWay`
and `comparesEqual` as the names for (1), I do not see any problems in
implementing `qCompareThreeWay` as (4).

Later we can also add `qComparesEqual` for consistency and even provide
3-arg overloads for string-like types, like Marc suggests.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Ivan 
Solovev via Development 
Sent: Thursday, September 21, 2023 10:43 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

> I have just rebased the chain on top of the latest dev and fixed the issue
> with qfloat16 and -Wfloat-equal.
> Now it builds fine for me locally on Linux with GCC. Started a full pre-check
> in the CI to test other configurations.
> I'll keep an eye on the pre-check results and try to fix any other errors,
> if they occur.

The qfloat16 patch does have some issues, because MSVC behaves differently from
other compilers. That's something that needs a deeper investigation.

Meanwhile, the full CI pre-check for the previous patch in the chain has
completed successfully.
So, you can use https://codereview.qt-project.org/c/qt/qtbase/+/479395 to
test the approach.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Thiago 
Macieira 
Sent: Thursday, September 21, 2023 2:22 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 20 September 2023 02:53:37 PDT Volker Hilsheimer via Development
wrote:
> If we can have (1), i.e.
>
> using Qt::equals;
> equals(a, b);
>
> why do we need qEquals?

See my other email: the (1) is not discoverable, teachable, or particularly
understandable by average C++ developers. It is not a good corner of C++.

(4) (the convenience function) is what users expect. Except that we don't need
it to be called qEquals, because we have an even better name for it:

operator==

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-21 Thread Ivan Solovev via Development
> I have just rebased the chain on top of the latest dev and fixed the issue
> with qfloat16 and -Wfloat-equal.
> Now it builds fine for me locally on Linux with GCC. Started a full pre-check
> in the CI to test other configurations.
> I'll keep an eye on the pre-check results and try to fix any other errors,
> if they occur.

The qfloat16 patch does have some issues, because MSVC behaves differently from
other compilers. That's something that needs a deeper investigation.

Meanwhile, the full CI pre-check for the previous patch in the chain has
completed successfully.
So, you can use https://codereview.qt-project.org/c/qt/qtbase/+/479395 to
test the approach.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Thiago 
Macieira 
Sent: Thursday, September 21, 2023 2:22 AM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 20 September 2023 02:53:37 PDT Volker Hilsheimer via Development
wrote:
> If we can have (1), i.e.
>
> using Qt::equals;
> equals(a, b);
>
> why do we need qEquals?

See my other email: the (1) is not discoverable, teachable, or particularly
understandable by average C++ developers. It is not a good corner of C++.

(4) (the convenience function) is what users expect. Except that we don't need
it to be called qEquals, because we have an even better name for it:

operator==

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Thiago Macieira
On Wednesday, 20 September 2023 02:53:37 PDT Volker Hilsheimer via Development 
wrote:
> If we can have (1), i.e.
> 
> using Qt::equals;
> equals(a, b);
> 
> why do we need qEquals?

See my other email: the (1) is not discoverable, teachable, or particularly 
understandable by average C++ developers. It is not a good corner of C++. 

(4) (the convenience function) is what users expect. Except that we don't need 
it to be called qEquals, because we have an even better name for it: 

operator==

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Thiago Macieira
On Thursday, 14 September 2023 03:47:05 PDT Marc Mutz via Development wrote:
> Whenever you want to add an operation to _all_ types in the C++,
> built-in, as well as user-defined one, you obviously cannot use
> something that only works in classes: member functions don't work and
> neither do class-static functions. Simply because you can add neither to
> the type `int`, or the type `int[10]`.

Right, but the number of primitive types is limited, so we can exhaustively 
cover them with our implementation. That only leaves non-primitives, which can 
use member functions (whether static or not). But I have nothing against 
friend or hidden friend functions found by ADL.

> The gold standard, crystallized from 30 years of C++ experience _and_ 30
> years of Qt experience, requires four things:
> 
> 1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
> 2. an implementation for built-in types: `std::swap`
> 3. an implementation for user-defined types: ADL `swap`
> 4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`

That gold standard is horrible API. I'm not disputing it's the gold standard, 
I'm simply saying it's horrible API because people don't write "using 
std::swap; swap". That necessary trick is not discoverable until you've seen 
yourself, leads to pitfalls, and is must always be explained when taught, 
because it's not obvious why it's necessary. ADL is not the simplest portion 
of the language.

Therefore,

> In addition, experience tells us that we cannot afford to use the
> convenience wrapper outside generic code, because it's too slow to
> compile (cf. https://codereview.qt-project.org/q/topic:qSwap).

teachability, readability, and discoverability trump compilation speed. 
Compilation speed is important, but it's not more important than designing a 
good API. If it takes CPU time to compile good code, then so be it.

Exhibit A: ranges.

Ivan wrote:
> One more question here - do we want our users to be able to do (1), or
> is it enough to expose only (4) to them?
> The reason for my question is (again) naming, see below.

We can go with (4) only for now, to have good API. If we need to because it's 
unacceptably slow, we can then make (1) public, though we'd have to have 
chosen an acceptable API for it or we'd have to go and change it so it could 
be made public.


There's no conclusion in what direction to take in your email. I don't see 
anything that would refute my conclusions.
-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Thiago Macieira
On Wednesday, 20 September 2023 07:35:24 PDT Marc Mutz via Development wrote:
> But, as mentioned in this thread some weeks ago, we're currently lacking
> public efficient API for "op== with Qt::CaseInsensitive". For the same
> reason we need equal^WcomparesEqual and can't rely solely on
> order^WcompareThreeWay, we need a standard way to have parametrized
> checks for equality. I was also mentioning fuzzy comparisons for FP
> types. Yes, we can again add QString::equals(), with the same problem
> for both non-generic and generic code as with the current
> QString{,View}::compare(). Or we use equal^WcomparesEqual overloads with
> additional arguments and a kernel for qComparesEqualMulti that does the
> moral equivalent of
> 
> using Qt::equal;
> if constexpr (qxp::is_detected_v decltype(lhs), decltype(rhs), decltype(extraArgs)...)) { // for each
> subset of extraTypes...
> if (!equals(lhs, rhs, extraArgs...)) return false;
> } else {
> if (!equals(lhs, rhs)) return false;
> }
> }

Sorry, I don't think we need any of this.

Case-insensitive comparison is rare. It's expensive and must be used only 
where necessary. And more importantly, it's done ONLY with QString or maybe 
its Views, so there's no need to go generic. There's no case-insensitive 
comparison of Pixmaps or floating point.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Ivan Solovev via Development
> We did _not_ deprecate qSwap().

Well, the source code shows that it _is_ deprecated:
<https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qswap.qdoc>
https://code.qt.io/cgit/qt/qtbase.git/tree/src/corelib/global/qswap.qdoc

I was not able to find a documentation page for qSwap in Qt 6.5,
but here's the link to 6.2: 
https://doc.qt.io/qt-6.2/qtalgorithms-obsolete.html#qSwap

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Marc Mutz 
via Development 
Sent: Wednesday, September 20, 2023 5:25 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On 20.09.23 14:42, Ivan Solovev via Development wrote:
> We have deprecated qSwap()

FTR:

We did _not_ deprecate qSwap(). We banned it from inline Qt code when we
know we can use one of the other ways:

- lhs.swap(rhs);
- std::swap(lhs, rhs);
- qt_ptr_swap(lhs, rhs);

We still use it in generic code, e.g. QList().

--
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
https://eur01.safelinks.protection.outlook.com/?url=http%3A%2F%2Fwww.qt.io%2F=05%7C01%7Civan.solovev%40qt.io%7C39da86d7aa2a4531845d08dbb9ee2348%7C20d0b167794d448a9d01aaeccc1124ac%7C0%7C0%7C638308204676895209%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C=wQIWQCOhPEs0IiKdpvAgU1pOqotlP3eOSFHFr%2B7UdFM%3D=0<http://www.qt.io/>

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

--
Development mailing list
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


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Marc Mutz via Development
On 20.09.23 14:42, Ivan Solovev via Development wrote:
> We have deprecated qSwap()

FTR:

We did _not_ deprecate qSwap(). We banned it from inline Qt code when we 
know we can use one of the other ways:

- lhs.swap(rhs);
- std::swap(lhs, rhs);
- qt_ptr_swap(lhs, rhs);

We still use it in generic code, e.g. QList().

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Marc Mutz via Development
On 20.09.23 14:42, Ivan Solovev via Development wrote:
[...]
>  > O = compareThreeWay, following std::compare_three_way 
> (https://en.cppreference.com/w/cpp/utility/compare/compare_three_way)
>  > E = comparesEqual
>  >
>  > The vast majority of code will use operators to compare two objects.
>  > Code that somehow needs the concept spelled out can type it out as well.
>  > In contrast to `swap` we don’t need to be short here, given that the 
> operator-shorthand exists.
> 
> Nice suggestion, thanks! Works for me!

Yes, that would work for me, too.

>  > why do we need qEquals?
> 
> Actually, I have the same question. That's why I wrote that we might 
> decide to not provide (4) at all.
> We have deprecated qSwap() and explicitly recommend using
> 
>      using std::swap;
>      swap(lhs, rhs);
> 
> instead. So why should we act differently for comparison?

As a first approximation, it's convenience around the 
using+non-qualified call. And that convenience is substantial, just try 
to calculate the noexcept for that yourself to see why (qSwap() does it, 
in case you want to peek at the solution, as does C++17 with 
is_nothrow_swappable).

But, as mentioned in this thread some weeks ago, we're currently lacking 
public efficient API for "op== with Qt::CaseInsensitive". For the same 
reason we need equal^WcomparesEqual and can't rely solely on 
order^WcompareThreeWay, we need a standard way to have parametrized 
checks for equality. I was also mentioning fuzzy comparisons for FP 
types. Yes, we can again add QString::equals(), with the same problem 
for both non-generic and generic code as with the current 
QString{,View}::compare(). Or we use equal^WcomparesEqual overloads with 
additional arguments and a kernel for qComparesEqualMulti that does the 
moral equivalent of

using Qt::equal;
if constexpr (qxp::is_detected_vhttps://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Ivan Solovev via Development
Hi,

> Given the state of https://codereview.qt-project.org/c/qt/qtbase/+/481410/3 
> right now (needs rebase, doesn’t build with either C++17 or C++20 for me on 
> macOS with apple’s clang)

I have just rebased the chain on top of the latest dev and fixed the issue with 
qfloat16 and -Wfloat-equal.
Now it builds fine for me locally on Linux with GCC. Started a full pre-check 
in the CI to test other configurations.
I'll keep an eye on the pre-check results and try to fix any other errors, if 
they occur.

> O = compareThreeWay, following std::compare_three_way 
> (https://en.cppreference.com/w/cpp/utility/compare/compare_three_way)
> E = comparesEqual
>
> The vast majority of code will use operators to compare two objects.
> Code that somehow needs the concept spelled out can type it out as well.
> In contrast to `swap` we don’t need to be short here, given that the 
> operator-shorthand exists.

Nice suggestion, thanks! Works for me!

> why do we need qEquals?

Actually, I have the same question. That's why I wrote that we might decide to 
not provide (4) at all.
We have deprecated qSwap() and explicitly recommend using

using std::swap;
swap(lhs, rhs);

instead. So why should we act differently for comparison?

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Volker 
Hilsheimer via Development 
Sent: Wednesday, September 20, 2023 11:53 AM
To: Marc Mutz ; development@qt-project.org 

Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)


On 19 Sep 2023, at 15:49, Marc Mutz via Development 
 wrote:
So I ask: Please let us roll out the framework with one of
equal/eq/order/ordering/cmp (your choice, but quickly!), to set a status
quo against which to benchmark any potentially-superior solutions, and
then the ML can finish bikesheddding and if the discussion yields
something better, I think I speak for Ivan, too, when I say that we're
committed to porting to that.

Thanks,
Marc


Given the state of https://codereview.qt-project.org/c/qt/qtbase/+/481410/3 
right now (needs rebase, doesn’t build with either C++17 or C++20 for me on 
macOS with apple’s clang), my suggestion would be to go “very explicit" with 
the names for O and E, at least for the time being.

O = compareThreeWay, following std::compare_three_way 
(https://en.cppreference.com/w/cpp/utility/compare/compare_three_way)
E = comparesEqual


The vast majority of code will use operators to compare two objects. Code that 
somehow needs the concept spelled out can type it out as well. In contrast to 
`swap` we don’t need to be short here, given that the operator-shorthand exists.

Once the chain of commits is up-to-date it will be easier to play around with 
alternatives, to see if we can come up with a technical solution that allows us 
to use `equals` and `compare` as names for E and O, as those are established 
APIs in Qt.


You lost me here, but I assume that you're talking about what I call
(4). There must be _one_ global template. It calls (2) or (3) via (1).
Everything else is a novel idea that must argue against 30 years of C++
and 30 years of Qt experience. qFoo would be that (4). A class-static
cannot be that (4).

Yes, I’m not questioning that we need Qt::equals. But do we need (4)? you 
marked it as optional yourself.

If we can have (1), i.e.

using Qt::equals;
equals(a, b);

why do we need qEquals?

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-20 Thread Volker Hilsheimer via Development

On 19 Sep 2023, at 15:49, Marc Mutz via Development 
 wrote:
So I ask: Please let us roll out the framework with one of
equal/eq/order/ordering/cmp (your choice, but quickly!), to set a status
quo against which to benchmark any potentially-superior solutions, and
then the ML can finish bikesheddding and if the discussion yields
something better, I think I speak for Ivan, too, when I say that we're
committed to porting to that.

Thanks,
Marc


Given the state of https://codereview.qt-project.org/c/qt/qtbase/+/481410/3 
right now (needs rebase, doesn’t build with either C++17 or C++20 for me on 
macOS with apple’s clang), my suggestion would be to go “very explicit" with 
the names for O and E, at least for the time being.

O = compareThreeWay, following std::compare_three_way 
(https://en.cppreference.com/w/cpp/utility/compare/compare_three_way)
E = comparesEqual


The vast majority of code will use operators to compare two objects. Code that 
somehow needs the concept spelled out can type it out as well. In contrast to 
`swap` we don’t need to be short here, given that the operator-shorthand exists.

Once the chain of commits is up-to-date it will be easier to play around with 
alternatives, to see if we can come up with a technical solution that allows us 
to use `equals` and `compare` as names for E and O, as those are established 
APIs in Qt.


You lost me here, but I assume that you're talking about what I call
(4). There must be _one_ global template. It calls (2) or (3) via (1).
Everything else is a novel idea that must argue against 30 years of C++
and 30 years of Qt experience. qFoo would be that (4). A class-static
cannot be that (4).

Yes, I’m not questioning that we need Qt::equals. But do we need (4)? you 
marked it as optional yourself.

If we can have (1), i.e.

using Qt::equals;
equals(a, b);

why do we need qEquals?

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-19 Thread Marc Mutz via Development
On 19.09.23 15:09, Volker Hilsheimer wrote:
[...]
> What Thiago wrote makes sense to me:
> 
>> On 31 Jul 2023, at 17:23, Thiago Macieira  wrote:
> 
>> I'm not saying we have to. I'm saying that we should provide as API for our
>> comparable types:
>> * compare()
>> * equals()
>> * operators
>>
>> Whether the implementation of the latter uses the former two directly is to 
>> be
>> seen.
> 
> 
> Separating the implementation from the public API seems to me the only way to 
> end up with a clean public API, while at the same time have a macro-friendly 
> convention. The implementation can live in a private function with a name not 
> suitable for a public API, e.g. “qt_equals/qt_compare”; those can be used by 
> the macro declaring the operators.
> 
> Types for which we then want public APIs as well (and I agree that it’s 
> strongly preferable to have this for all relevant types in the long run) can 
> declare public equals()/compare() functions that ideally use the private 
> functions.

We already have QString::compare() as an example how to _not_ do this 
kind of API: it's an absolute catastrophe: What is a user to use? 
QString::compare()? QStringView::compare()? 
QLatin1StringView::compare()? Each one works for a certain set of 
argument types, none works for all. And that's even "concrete" code. If 
we're taking generic code into account, it gets totally unworkable: It 
makes helper functions a la qHashMulti() impossible to write.

Remember that the overarching goal is to make the implementation and 
documentation of the relational operators for Qt types _easy_. That 
means we provide the macros for defining the public interface, and 
documentation, but we also need to provide such implementation helpers 
as qHashMulti() to help implement the required two functions. That, in 
turn, requires a _uniform_ interface to the functionality. Besides, if 
we require every class author to maintain a separate, public API on top 
of what the macros need and provide, we lose simplicity. And since it's 
now up to the class author to pick a name and document the function, we 
also lose consistency.

> I do not see the need for adding more qOperator type global functions.

You lost me here, but I assume that you're talking about what I call 
(4). There must be _one_ global template. It calls (2) or (3) via (1). 
Everything else is a novel idea that must argue against 30 years of C++ 
and 30 years of Qt experience. qFoo would be that (4). A class-static 
cannot be that (4).

Taking a step back:

 From my POV, we had good names lined up for 6.6: Qt::order/ing, 
Qt::equal, qOrder, qEqual, etc. They were chosen _because_ they meet all 
requirements and they model what we and C++ already have for swap(). 
They don't pessimise KDE types vs. Qt types. Whatever we choose will 
become consistent simply by being available for virtually all Qt types, 
eventually. I expect all bike-shedding to meet the constraints laid out. 
Demanding the impossible is not helpful.

We need this framework to check our operators for symmetry before we can 
claim C++20 compatibility (we're already getting BRs about 5.15 not 
compiling with C++20), and this discussion is holding up that work, 
which was planned for 6.6 and now we're close to missing 6.7, too.

We _know_ equal/eq/order/ordering/cmp _work_. Ivan and I did the work. 
If anyone thinks they can come up with better names, don't just throw 
your hat into the ring. Code it for out for a few classes. Incl. 
QString, of course.

So I ask: Please let us roll out the framework with one of 
equal/eq/order/ordering/cmp (your choice, but quickly!), to set a status 
quo against which to benchmark any potentially-superior solutions, and 
then the ML can finish bikesheddding and if the discussion yields 
something better, I think I speak for Ivan, too, when I say that we're 
committed to porting to that.

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-19 Thread Volker Hilsheimer via Development
> On 18 Sep 2023, at 14:46, Marc Mutz via Development 
>  wrote:
> 
> TL;DR: "a" must not be a name of an existing function in Qt.
> 
> On 18.09.23 10:15, Ivan Solovev via Development wrote:
>> Hi,
>> 
>>> 1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
>>> 2. an implementation for built-in types: `std::swap`
>>> 3. an implementation for user-defined types: ADL `swap`
>>> 4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`
>> 
>> One more question here - do we want our users to be able to do (1), or
>> is it enough to expose only (4) to them?
>> The reason for my question is (again) naming, see below.

[…]

>> Anyway, it would be great to come to some kind of consensus about the
>> naming of the APIs, and move on to the actual implementation.
> 
> +1


My take from this is that it’s next to impossible to reconcile the technical 
arguments for an unused (even if ugly) function name with having a good public 
API for our types. Not adding named public functions that are equivalent to 
C++20’s spaceship operator makes the problem less complex, but also reduces the 
value of doing the work to the point where it’s not worth it until we require 
C++20.

What Thiago wrote makes sense to me:

> On 31 Jul 2023, at 17:23, Thiago Macieira  wrote:

> I'm not saying we have to. I'm saying that we should provide as API for our 
> comparable types:
> * compare()
> * equals()
> * operators
> 
> Whether the implementation of the latter uses the former two directly is to 
> be 
> seen.


Separating the implementation from the public API seems to me the only way to 
end up with a clean public API, while at the same time have a macro-friendly 
convention. The implementation can live in a private function with a name not 
suitable for a public API, e.g. “qt_equals/qt_compare”; those can be used by 
the macro declaring the operators.

Types for which we then want public APIs as well (and I agree that it’s 
strongly preferable to have this for all relevant types in the long run) can 
declare public equals()/compare() functions that ideally use the private 
functions.

I do not see the need for adding more qOperator type global functions.


Volker

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-18 Thread Marc Mutz via Development
TL;DR: "a" must not be a name of an existing function in Qt.

On 18.09.23 10:15, Ivan Solovev via Development wrote:
> Hi,
> 
>  > 1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
>  > 2. an implementation for built-in types: `std::swap`
>  > 3. an implementation for user-defined types: ADL `swap`
>  > 4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`
> 
> One more question here - do we want our users to be able to do (1), or
> is it enough to expose only (4) to them?
> The reason for my question is (again) naming, see below.

I see no reason to withhold the like of KDE an API to adapt their types 
to C++20 semantics while at the same time maintaining compatibility with 
C++17. But if we can't agree on naming otherwise, then I guess we'll 
have to make it private and KDE will use it anyway, and everyone will 
wish we had made it public.

>  > My original proposal had, for equality, a = equal, b = Qt, c = qEquals,
>  > and for ordered types, a = order, b = Qt and c = qOrder (or qCompare,
>  > don't remember which).
> 
> I was about to suggest a = `qt_equals`, b = `Qt`, c = `qEquals`, but that
> would result in ugly `Qt::qt_equals()` calls.
> 
> But if we say that the users should only use `qEquals()` and `qCompare` in
> their code, then we can use ||`QtPrivate` as the namespace​:
> a = `qt_equals`,    b = `QtPrivate`, c = `qEquals` for equality, and
> a = `qt_compare`, b = `QtPrivate`, c = `qCompare` for ordering.
> 
> AFAIK, the most critical drawback of qSwap() was the compilation speed
> when having it in every value class, so I would not expect Qt itself to use
> `qEquals` and `qCompare` everywhere.
> But would it be ok for the user code?
> 
> What do you think?

I think that users like KDE that have large Qt-based class libraries and 
traditionally use our class implementation macros no matter what we say, 
will want to be treated like a Qt module, so requiring them to only use 
(4) while we ban the use of (4) in most Qt code, is not going to amuse 
them.

> Other idea that came to my mind while writing this - just do not provide 
> (4),

That is also an option.

> since it has known issues (at least with compilation speed). Then we can
> use
> a = `qEquals`, b = `Qt` for equality, and
> a = `qCompare`, b = `Qt` for ordering.
> We already have `QTest::qCompare()`, so `Qt::qCompare` would not be
> a much worse naming.

I don't really want to think about the implications of an ADL-enabled 
qCompare() on code in the QTest namespace... I don't think we should 
afford ourselves the inconveniences of unintended overloading.

Remember the problem with equals() and compare(): we have classes with 
these functions, and, regardless of whether they're static or 
non-static, binary non-member or unary member functions; name lookup 
will _stop_ at class scope when it finds the name, and it will _not_ 
continue to look in outer scopes just because the arity or argument 
types don't match. You will just get a compile error (if lucky) or 
something unexpected called (if not). Yet, that is exactly what we need 
for the case where func(A, B) is resolved in terms of func(A, A(B)) 
(implicit conversions).

qCompare() may have the same problem.

> Anyway, it would be great to come to some kind of consensus about the
> naming of the APIs, and move on to the actual implementation.

+1

Thanks,
Marc

-- 
Marc Mutz 
Principal Software Engineer

The Qt Company
Erich-Thilo-Str. 10 12489
Berlin, Germany
www.qt.io

Geschäftsführer: Mika Pälsi, Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht Charlottenburg,
HRB 144331 B

-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-18 Thread Ivan Solovev via Development
Hi,

> 1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
> 2. an implementation for built-in types: `std::swap`
> 3. an implementation for user-defined types: ADL `swap`
> 4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`

One more question here - do we want our users to be able to do (1), or
is it enough to expose only (4) to them?
The reason for my question is (again) naming, see below.

> My original proposal had, for equality, a = equal, b = Qt, c = qEquals,
> and for ordered types, a = order, b = Qt and c = qOrder (or qCompare,
> don't remember which).

I was about to suggest a = `qt_equals`, b = `Qt`, c = `qEquals`, but that
would result in ugly `Qt::qt_equals()` calls.

But if we say that the users should only use `qEquals()` and `qCompare` in
their code, then we can use `QtPrivate` as the namespace​:
a = `qt_equals`,b = `QtPrivate`, c = `qEquals` for equality, and
a = `qt_compare`, b = `QtPrivate`, c = `qCompare` for ordering.

AFAIK, the most critical drawback of qSwap() was the compilation speed
when having it in every value class, so I would not expect Qt itself to use
`qEquals` and `qCompare` everywhere.
But would it be ok for the user code?

What do you think?

Other idea that came to my mind while writing this - just do not provide (4),
since it has known issues (at least with compilation speed). Then we can
use
a = `qEquals`, b = `Qt` for equality, and
a = `qCompare`, b = `Qt` for ordering.
We already have `QTest::qCompare()`, so `Qt::qCompare` would not be
a much worse naming.

Anyway, it would be great to come to some kind of consensus about the
naming of the APIs, and move on to the actual implementation.

Best regards,
Ivan

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Marc Mutz 
via Development 
Sent: Thursday, September 14, 2023 12:47 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

Hi,

Sorry for being absent this discussion for the last months, but getting
6.6 in shape was more pressing than even fundamental 6.7 work.

Whenever you want to add an operation to _all_ types in the C++,
built-in, as well as user-defined one, you obviously cannot use
something that only works in classes: member functions don't work and
neither do class-static functions. Simply because you can add neither to
the type `int`, or the type `int[10]`.

The gold standard, crystallized from 30 years of C++ experience _and_ 30
years of Qt experience, requires four things:

1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
2. an implementation for built-in types: `std::swap`
3. an implementation for user-defined types: ADL `swap`
4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`

In addition, experience tells us that we cannot afford to use the
convenience wrapper outside generic code, because it's too slow to
compile (cf. https://codereview.qt-project.org/q/topic:qSwap).

This gold standard has three variables: the names
a. `swap` for the implementation functions (2+3)
b. `std` as the namespace containing the impl for built-ins (2)
c. `std::ranges::swap`/`qSwap` as the name of the convenience wrapper

Within this framework, we're basically free to pick any names, though
`Qt` is probably set as the name of the namespace containing the impl
for built-in types (2).

My original proposal had, for equality, a = equal, b = Qt, c = qEquals,
and for ordered types, a = order, b = Qt and c = qOrder (or qCompare,
don't remember which).

Within the framework, I don't really care about the names.

The rest of the email is only interesting if you disagree with the
algorithm laid out so far.

Thanks,
Marc

So, you disagree with the framework as-is. Each puzzle piece has it's
place there, though, and I believe it's minimal, so you're free to poke
holes into it, if you can. Here are a few rebuttals for replies I
anticipate:

"We don't need (1), we can just always call std::swap".

This means all user-defined types would have to either specialize
std::swap (only possible for concrete types, there's no partial
specialization for function templates) or overload it (in namespace
std). If we do that, it would work, but it wouldn't solve the problem of
the pages of error messages thrown at users when they get it wrong. We
need hidden friend for that, and hidden friend are only found via ADL
and ADL is only active for non-qualified calls, and a name with `::` is
a qualified name, and so ADL doesn't kick in.

"We can put swap() at the global namespace, then, and always call
swap(lhs, rhs)."

This would require us to 

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-09-14 Thread Marc Mutz via Development
Hi,

Sorry for being absent this discussion for the last months, but getting 
6.6 in shape was more pressing than even fundamental 6.7 work.

Whenever you want to add an operation to _all_ types in the C++, 
built-in, as well as user-defined one, you obviously cannot use 
something that only works in classes: member functions don't work and 
neither do class-static functions. Simply because you can add neither to 
the type `int`, or the type `int[10]`.

The gold standard, crystallized from 30 years of C++ experience _and_ 30 
years of Qt experience, requires four things:

1. an ADL-able calling convention:   `using std::swap; swap(lhs, rhs);`
2. an implementation for built-in types: `std::swap`
3. an implementation for user-defined types: ADL `swap`
4. (optionally) a convenience wrapper: `std::ranges::swap()`, `qSwap`

In addition, experience tells us that we cannot afford to use the 
convenience wrapper outside generic code, because it's too slow to 
compile (cf. https://codereview.qt-project.org/q/topic:qSwap).

This gold standard has three variables: the names
a. `swap` for the implementation functions (2+3)
b. `std` as the namespace containing the impl for built-ins (2)
c. `std::ranges::swap`/`qSwap` as the name of the convenience wrapper

Within this framework, we're basically free to pick any names, though 
`Qt` is probably set as the name of the namespace containing the impl 
for built-in types (2).

My original proposal had, for equality, a = equal, b = Qt, c = qEquals, 
and for ordered types, a = order, b = Qt and c = qOrder (or qCompare, 
don't remember which).

Within the framework, I don't really care about the names.

The rest of the email is only interesting if you disagree with the 
algorithm laid out so far.

Thanks,
Marc

So, you disagree with the framework as-is. Each puzzle piece has it's 
place there, though, and I believe it's minimal, so you're free to poke 
holes into it, if you can. Here are a few rebuttals for replies I 
anticipate:

"We don't need (1), we can just always call std::swap".

This means all user-defined types would have to either specialize 
std::swap (only possible for concrete types, there's no partial 
specialization for function templates) or overload it (in namespace 
std). If we do that, it would work, but it wouldn't solve the problem of 
the pages of error messages thrown at users when they get it wrong. We 
need hidden friend for that, and hidden friend are only found via ADL 
and ADL is only active for non-qualified calls, and a name with `::` is 
a qualified name, and so ADL doesn't kick in.

"We can put swap() at the global namespace, then, and always call 
swap(lhs, rhs)."

This would require us to have a q/q_/qt_ prefix, but we might want that, 
anyway, so not really a problem there. But this has the same problem 
with 100s of overloads and the compiler printing them all on error. In 
addition, I _think_ (and the language lawyers can speak up whether I'm 
right or wrong), name lookup will go up the scopes, find (one of the) 
`swap`s at the global scope and stop there. Since it found something, it 
will not consider ADL.

If you have more, let's hear it.

Thanks,
Marc

On 17.08.23 19:41, Thiago Macieira wrote:
> On Monday, 14 August 2023 03:16:37 PDT Ivan Solovev via Development wrote:
>>> What I meant is that the product API of using the macros are the set of
>>> operators. The methods that those operators called are not API and users
>>> are not expected to use them in their code. In fact, if conflicting names
>>> are a problem, then we should uglify the names we're asking for in the
>>> macros by inserting a "q_" or "qt_" prefix.
>>>
>>> This means C++17 users are able to use all operators to produce a boolean
>>> result, but can't get a QXxxOrdering result with homogeneous API from the
>>> macros.
>>
>> The new macros are supposed to be publicly available. This means that the
>> users will be able to use them in their custom classes to implement the
>> unified comparison behavior between C++17 and C++20.
>>
>> This means that the users will need to provide their implementations of
>> the helper methods. The idea is to explicitly mention it in the docs,
>> so the methods cannot be considered "Qt internal" anymore.
>> Can we use the "q_" or "qt_" prefix for these helper functions in this case?
> 
> The methods aren't "Qt internal" but they they don't have to be API either for
> those libraries any more than they have to for us. They are used by library
> implementers (like us), so an uglier name is not a big deal.
> 
> But maybe we should opt for a name like qHash and the older qLess.
> 
>> Or do you suggest making the macros Qt-private? Not that we *really* can
>> do it, because the macros are exposed in public headers, but we can at least
>> hide the documentation, and do not advertise the macros...
>> But IMO such decision would significantly decrease the value of the new
>> feature.
> 
> I'm unsure. How widely used is this going to be even inside 

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-08-17 Thread Thiago Macieira
On Monday, 14 August 2023 03:16:37 PDT Ivan Solovev via Development wrote:
> > What I meant is that the product API of using the macros are the set of
> > operators. The methods that those operators called are not API and users
> > are not expected to use them in their code. In fact, if conflicting names
> > are a problem, then we should uglify the names we're asking for in the
> > macros by inserting a "q_" or "qt_" prefix.
> > 
> > This means C++17 users are able to use all operators to produce a boolean
> > result, but can't get a QXxxOrdering result with homogeneous API from the
> > macros.
> 
> The new macros are supposed to be publicly available. This means that the
> users will be able to use them in their custom classes to implement the
> unified comparison behavior between C++17 and C++20.
> 
> This means that the users will need to provide their implementations of
> the helper methods. The idea is to explicitly mention it in the docs,
> so the methods cannot be considered "Qt internal" anymore.
> Can we use the "q_" or "qt_" prefix for these helper functions in this case?

The methods aren't "Qt internal" but they they don't have to be API either for 
those libraries any more than they have to for us. They are used by library 
implementers (like us), so an uglier name is not a big deal.

But maybe we should opt for a name like qHash and the older qLess.

> Or do you suggest making the macros Qt-private? Not that we *really* can
> do it, because the macros are exposed in public headers, but we can at least
> hide the documentation, and do not advertise the macros...
> But IMO such decision would significantly decrease the value of the new
> feature.

I'm unsure. How widely used is this going to be even inside Qt? Have you found 
any use for it inside Qt Creator?

I can actually see this more used in the KF6 libraries than in Qt Creator 
because they are libraries (Qt Creator has some, but they are all internal 
with in-tree users). We may want to keep them documented with \internal for 
the first release and take a look if we find uses for it outside of Qt. That 
way 
we can also collect any issues with colliding symbol names and adapt them 
before having to guarantee source compatibility.

> > We still need *some* level of public API to produce ordering results
> > because users will need those methods to produce their own comparison
> > functions, such as composing on top of our string or date/time classes.
> > If they want to also be compatible with C++17, then they can't use the
> > spaceship, and instead they will need to call a named function of some
> > sorts. If we are going to expose API, then said API must have proper
> > names and thus must be "equals" and "compare".
> 
> The initial idea was that the helper functions could also become the public
> API for producing ordering results. IIUC, that's also why Marc suggested to
> make them hidden friends. Using private 2-arg static function would work for
> the comparison operators but wouldn't work as a public API. Hidden friends
> will work for both cases.

And I think it's a good idea for there to be a public function users can use 
in C++17 mode. But as I said, that requires them to have proper names. Whether 
they are the same functions that the macros call is up for debate. They don't 
have to be: one set can call the other without trouble, just with a bit of 
boilerplate.

The question to answer is whether we want to support users writing generic 
code in C++17 mode (i.e., without the spaceship). I don't particularly think 
it's necessary and thus don't think it compels us to make compromises in our 
API for this use-case. Third party code would either need to require C++20 or 
forego the ability to be generic. So like above: I think we need to know 
whether there's any real use out there of this.

If we do think we should provide a generic API, then I'd argue such API should 
be namespaced with a "q" prefix: qEquals and qCompare (note: we have 
QTest::qCompare, but I don't think there's any clash).

> If we advertise only the public API which is not supported by the macros,
> then the users will still need to implement all six (or 12 in case of
> mixed-type comparison) relational operators instead of just calling one
> macro and implementing two helper functions.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-08-14 Thread Ivan Solovev via Development
I'm now re-reading the discussion, and I think that I missed one thing
previously, so let me comment on that.

> What I meant is that the product API of using the macros are the set of
> operators. The methods that those operators called are not API and users are
> not expected to use them in their code. In fact, if conflicting names are a
> problem, then we should uglify the names we're asking for in the macros by
> inserting a "q_" or "qt_" prefix.
>
> This means C++17 users are able to use all operators to produce a boolean
> result, but can't get a QXxxOrdering result with homogeneous API from the
> macros.

The new macros are supposed to be publicly available. This means that the
users will be able to use them in their custom classes to implement the
unified comparison behavior between C++17 and C++20.

This means that the users will need to provide their implementations of
the helper methods. The idea is to explicitly mention it in the docs,
so the methods cannot be considered "Qt internal" anymore.
Can we use the "q_" or "qt_" prefix for these helper functions in this case?

Or do you suggest making the macros Qt-private? Not that we *really* can
do it, because the macros are exposed in public headers, but we can at least
hide the documentation, and do not advertise the macros...
But IMO such decision would significantly decrease the value of the new
feature.

> We still need *some* level of public API to produce ordering results because
> users will need those methods to produce their own comparison functions, such
> as composing on top of our string or date/time classes. If they want to also
> be compatible with C++17, then they can't use the spaceship, and instead they
> will need to call a named function of some sorts. If we are going to expose
> API, then said API must have proper names and thus must be "equals" and
> "compare".

The initial idea was that the helper functions could also become the public
API for producing ordering results. IIUC, that's also why Marc suggested to
make them hidden friends. Using private 2-arg static function would work for
the comparison operators but wouldn't work as a public API. Hidden friends
will work for both cases.

If we advertise only the public API which is not supported by the macros,
then the users will still need to implement all six (or 12 in case of
mixed-type comparison) relational operators instead of just calling one macro
and implementing two helper functions.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B
____________
From: Development  on behalf of Thiago 
Macieira 
Sent: Tuesday, August 1, 2023 5:11 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Tuesday, 1 August 2023 01:55:05 PDT Ivan Solovev via Development wrote:
> > BTW, this needs to integrate with QEqualityOperatorForType and
> > QLessThanOperatorForType in qmetatype.h. I don't think there's any work
> > for
> > you other than verifying.
>
> I was not even aware of them, thanks! A brief look at the code shows that
> they shouldn't be affected, but I'll update the Jira ticket to keep them
> in mind.

I wasn't either. I went looking for qLess, which existed for Qt 3, 4 and 5 for
Q(Value)Map, and found them.

--
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-08-01 Thread Thiago Macieira
On Tuesday, 1 August 2023 01:55:05 PDT Ivan Solovev via Development wrote:
> > BTW, this needs to integrate with QEqualityOperatorForType and
> > QLessThanOperatorForType in qmetatype.h. I don't think there's any work
> > for
> > you other than verifying.
> 
> I was not even aware of them, thanks! A brief look at the code shows that
> they shouldn't be affected, but I'll update the Jira ticket to keep them
> in mind.

I wasn't either. I went looking for qLess, which existed for Qt 3, 4 and 5 for 
Q(Value)Map, and found them.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-08-01 Thread Ivan Solovev via Development
> Every pair? Under what conditions do we need to implement heterogeneous
> comparisons, outside of the primitives?

Well, it was not a very precise wording from my side.
What I mean is that we need to handle every class with existing relational
operators. Which looks like a lot of work, and adding a new function overload
on top of it makes it even worse.
I also had in mind cases like "QPoint vs QPointF" or "QSize vs QSizeF",
but I now see that we do not explicitly provide operators for such comparisons.
Instead, we rely on the implicit constructors to do the conversion.

> BTW, this needs to integrate with QEqualityOperatorForType and
> QLessThanOperatorForType in qmetatype.h. I don't think there's any work for
> you other than verifying.

I was not even aware of them, thanks! A brief look at the code shows that
they shouldn't be affected, but I'll update the Jira ticket to keep them
in mind.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

From: Development  on behalf of Edward 
Welbourne via Development 
Sent: Tuesday, August 1, 2023 9:17 AM
To: Macieira, Thiago ; development@qt-project.org 

Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Monday, 31 July 2023 02:36:41 PDT Ivan Solovev via Development wrote:
>> Basically, what you suggest is that for every pair of comparable Qt
>> types we would need to double the amount of work that we do - provide
>> not only the helper functions for the macros, but also the overload
>> for some public functions for the end-users.

Thiago Macieira (31 July 2023 17:23) replied:
> Every pair? Under what conditions do we need to implement
> heterogeneous comparisons, outside of the primitives? Even with the
> primitives, I don't see more than a handful of heterogeneous, between
> integers and floating point, plus a few other dispatchers to avoid
> ambiguous lookups for integer to integer.

There'd also be our plethora of string types - but still, indeed, only a
fairly limited set of cross-type comparisons.

Eddy.
--
Development mailing list
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


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-08-01 Thread Edward Welbourne via Development
On Monday, 31 July 2023 02:36:41 PDT Ivan Solovev via Development wrote:
>> Basically, what you suggest is that for every pair of comparable Qt
>> types we would need to double the amount of work that we do - provide
>> not only the helper functions for the macros, but also the overload
>> for some public functions for the end-users.

Thiago Macieira (31 July 2023 17:23) replied:
> Every pair? Under what conditions do we need to implement
> heterogeneous comparisons, outside of the primitives? Even with the
> primitives, I don't see more than a handful of heterogeneous, between
> integers and floating point, plus a few other dispatchers to avoid
> ambiguous lookups for integer to integer.

There'd also be our plethora of string types - but still, indeed, only a
fairly limited set of cross-type comparisons.

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-31 Thread Thiago Macieira
On Monday, 31 July 2023 02:36:41 PDT Ivan Solovev via Development wrote:
> > If we are going to expose
> > API, then said API must have proper names and thus must be "equals" and
> > "compare".
> > 
> > But again, these do not need to be the functions that the macros call
> > directly. The macros may call adaptor functions with ugly names.
> 
> What I cannot understand is why we should duplicate the functions? It would
> be much easier if we could use the same functions both for macros and the
> user-specific code.

I'm not saying we have to. I'm saying that we should provide as API for our 
comparable types:
* compare()
* equals()
* operators

Whether the implementation of the latter uses the former two directly is to be 
seen.

> Basically, what you suggest is that for every pair of comparable Qt types
> we would need to double the amount of work that we do - provide not only
> the helper functions for the macros, but also the overload for some
> public functions for the end-users.

Every pair? Under what conditions do we need to implement heterogeneous 
comparisons, outside of the primitives? Even with the primitives, I don't see 
more than a handful of heterogeneous, between integers and floating point, plus 
a few other dispatchers to avoid ambiguous lookups for integer to integer.

It's also not double the amount of work because clearly one set of functions 
would build on top of the other. It's a matter of adaptation in case the non-
ugly names can't be used by the macros.

> Of course, we could try to simplify it. I already started to introduce
> Qt::order() overloads for built-in types in [0].
> So, we could probably provide a general case like this:
> 
> template 
> auto order(const L , const R ) noexcept
> {
> // or any other uglified name that we choose
> return qt_order(lhs, rhs);
> }
> 
> and just let the template fail if qt_order() is not defined for L and R.
> 
> With such approach, we could use qt_equals() and qt_compare() as helper
> functions, and Qt::equals() and Qt::compare() as public API for the users.

Indeed.

BTW, this needs to integrate with QEqualityOperatorForType and 
QLessThanOperatorForType in qmetatype.h. I don't think there's any work for 
you other than verifying. I was looking for qLess, but we seem to have dropped 
it with the std::map rewrite for QMap.

> But then, if we use qt_*() functions, their names will not clash with any
> of the existing APIs, and we can just let the end-users use these
> functions directly.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-31 Thread Ivan Solovev via Development
> What I meant is that the product API of using the macros are the set of
> operators. The methods that those operators called are not API and users are
> not expected to use them in their code. In fact, if conflicting names are a
> problem, then we should uglify the names we're asking for in the macros by
> inserting a "q_" or "qt_" prefix.

I do not completely agree with that, see my arguments below.

> We still need *some* level of public API to produce ordering results because
> users will need those methods to produce their own comparison functions, such
> as composing on top of our string or date/time classes. If they want to also
> be compatible with C++17, then they can't use the spaceship, and instead they
> will need to call a named function of some sorts.

Right, totally agree with this part.

> If we are going to expose
> API, then said API must have proper names and thus must be "equals" and
> "compare".
>
> But again, these do not need to be the functions that the macros call
> directly. The macros may call adaptor functions with ugly names.

What I cannot understand is why we should duplicate the functions? It would
be much easier if we could use the same functions both for macros and the
user-specific code.

Basically, what you suggest is that for every pair of comparable Qt types
we would need to double the amount of work that we do - provide not only
the helper functions for the macros, but also the overload for some
public functions for the end-users.

Of course, we could try to simplify it. I already started to introduce
Qt::order() overloads for built-in types in [0].
So, we could probably provide a general case like this:

template 
auto order(const L , const R ) noexcept
{
// or any other uglified name that we choose
return qt_order(lhs, rhs);
}

and just let the template fail if qt_order() is not defined for L and R.

With such approach, we could use qt_equals() and qt_compare() as helper
functions, and Qt::equals() and Qt::compare() as public API for the users.

But then, if we use qt_*() functions, their names will not clash with any
of the existing APIs, and we can just let the end-users use these
functions directly.

[0]: https://codereview.qt-project.org/c/qt/qtbase/+/478199

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

____
From: Thiago Macieira
Sent: Wednesday, July 26, 2023 5:18 PM
To: development@qt-project.org
Cc: Ivan Solovev
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 26 July 2023 02:58:51 PDT Ivan Solovev via Development wrote:
> > That means it can't be used in ADL contexts without scope qualifications,
> > but I don't see that as an API requirement. The API should be the
> > operators.
> We introduce new public macros, which means that users will be using them in
> their custom classes in order to achieve the same unified comparison
> behavior between C++17 and C++20.
> This means that the users will have to implement the helper functions
> required for these macros. I agree that for the equal()/equals() helper
> function, the op==() and op!=() are mostly usable.
> But what about the order()/compare() function? I assume that the users would
> NOT be able to use op<=>(), because they will write C++17-compatible code.
> And testing for Unordered in terms of C++17 relational operators looks like
> an unnecessarily large amount of code, especially if we already have
> written this code for them. So why not just let them use it?
> Of course, you can argue that they can use the public APIs directly (if they
> exist). But what if the user develops a generic class?

What I meant is that the product API of using the macros are the set of
operators. The methods that those operators called are not API and users are
not expected to use them in their code. In fact, if conflicting names are a
problem, then we should uglify the names we're asking for in the macros by
inserting a "q_" or "qt_" prefix.

This means C++17 users are able to use all operators to produce a boolean
result, but can't get a QXxxOrdering result with homogeneous API from the
macros.

We still need *some* level of public API to produce ordering results because
users will need those methods to produce their own comparison functions, such
as composing on top of our string or date/time classes. If they want to also
be compatible with C++17, then they can't use the spaceship, and instead they
will need to call a named function of some sorts. If we are going to expose
API, then sa

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-26 Thread Thiago Macieira
On Wednesday, 26 July 2023 02:58:51 PDT Ivan Solovev via Development wrote:
> > That means it can't be used in ADL contexts without scope qualifications,
> > but I don't see that as an API requirement. The API should be the
> > operators.
> We introduce new public macros, which means that users will be using them in
> their custom classes in order to achieve the same unified comparison
> behavior between C++17 and C++20.
> This means that the users will have to implement the helper functions
> required for these macros. I agree that for the equal()/equals() helper
> function, the op==() and op!=() are mostly usable.
> But what about the order()/compare() function? I assume that the users would
> NOT be able to use op<=>(), because they will write C++17-compatible code.
> And testing for Unordered in terms of C++17 relational operators looks like
> an unnecessarily large amount of code, especially if we already have
> written this code for them. So why not just let them use it?
> Of course, you can argue that they can use the public APIs directly (if they
> exist). But what if the user develops a generic class?

What I meant is that the product API of using the macros are the set of 
operators. The methods that those operators called are not API and users are 
not expected to use them in their code. In fact, if conflicting names are a 
problem, then we should uglify the names we're asking for in the macros by 
inserting a "q_" or "qt_" prefix.

This means C++17 users are able to use all operators to produce a boolean 
result, but can't get a QXxxOrdering result with homogeneous API from the 
macros.

We still need *some* level of public API to produce ordering results because 
users will need those methods to produce their own comparison functions, such 
as composing on top of our string or date/time classes. If they want to also 
be compatible with C++17, then they can't use the spaceship, and instead they 
will need to call a named function of some sorts. If we are going to expose 
API, then said API must have proper names and thus must be "equals" and 
"compare".

But again, these do not need to be the functions that the macros call 
directly. The macros may call adaptor functions with ugly names.

> What we can do is to have both private/public static two-arg member and a
> hidden friend, which would simply call the static method. We will have to
> apply this hack only to the classes that already have public APIs with the
> clashing names. For other classes we can just use hidden friends directly.

I don't see the need for anything to be a hidden friend. We need a *name* that 
compiles, that's all.

> > You forgot the <=> 0 here. Comparing an int with 0 through the spaceship
> > operator produces a std::strong_ordering result. And comparing a
> > std::strong_ordering with 0 via the spaceship returns itself too.
> > 
> > https://gcc.godbolt.org/z/ebKe8Eb3a
> > 
> > This works for weak_ordering too. For partial_ordering, the case of
> > unordered needs to be handled explicitly, so I'd instead require that the
> > called function return either std::partial_ordering or QPartialOrdering,
> > nothing else.
> 
> Well, the idea was to avoid unnecessary operations, and basically optimize
> operator<=>() to simply call the helper function in C++20 case.

Agreed, but your argument does not refute my proposal. What I suggested is 
still optimal for strong and weak ordering.

The only problem is partial ordering because QPartialOrdering::Unordered's 
value does not match two of the three Standard Libraries' values (for Qt 7, we 
can fix this now that we know what those values are). And even then, this only 
applies if someone is actually storing that number or passing it through an 
opaque ABI boundary. If instead everything is inline, the compiler's optimiser 
should simply emit optimal code.

> But anyway, that's a nice approach, and I should consider using it in my
> patches. Specially if it allows us to "unblock" compare() as a name for the
> helper function.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-26 Thread Ivan Solovev via Development
> Ah, I see. It's not an ambiguous overload problem because the hidden friend is
> not even part of the overload set in the first place. That can be solved by
> promoting the function from hidden friend to static member, either as public
> or private, depending on the implementer's choice.
>
> That means it can't be used in ADL contexts without scope qualifications, but 
> I
> don't see that as an API requirement. The API should be the operators.

We introduce new public macros, which means that users will be using them in
their custom classes in order to achieve the same unified comparison behavior
between C++17 and C++20.
This means that the users will have to implement the helper functions required
for these macros. I agree that for the equal()/equals() helper function, the
op==() and op!=() are mostly usable.
But what about the order()/compare() function? I assume that the users would
NOT be able to use op<=>(), because they will write C++17-compatible code.
And testing for Unordered in terms of C++17 relational operators looks like an
unnecessarily large amount of code, especially if we already have written this
code for them. So why not just let them use it?
Of course, you can argue that they can use the public APIs directly (if they
exist). But what if the user develops a generic class?

What we can do is to have both private/public static two-arg member and a
hidden friend, which would simply call the static method. We will have to
apply this hack only to the classes that already have public APIs with the
clashing names. For other classes we can just use hidden friends directly.

> You forgot the <=> 0 here. Comparing an int with 0 through the spaceship
> operator produces a std::strong_ordering result. And comparing a
> std::strong_ordering with 0 via the spaceship returns itself too.
>
> https://gcc.godbolt.org/z/ebKe8Eb3a
>
> This works for weak_ordering too. For partial_ordering, the case of unordered
> needs to be handled explicitly, so I'd instead require that the called
> function return either std::partial_ordering or QPartialOrdering, nothing
> else.

Well, the idea was to avoid unnecessary operations, and basically optimize
operator<=>() to simply call the helper function in C++20 case.

But anyway, that's a nice approach, and I should consider using it in my
patches. Specially if it allows us to "unblock" compare() as a name for the
helper function.

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

____
From: Thiago Macieira
Sent: Tuesday, July 25, 2023 4:42 PM
To: development@qt-project.org
Cc: Ivan Solovev
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Tuesday, 25 July 2023 01:42:42 PDT Ivan Solovev via Development wrote:
> > And why is that a problem? So long as the proper overload exists, it'll be
> > called. There's only a problem if the overloads are ambiguous.
>
> The problem is that there might be no "proper" overload, but the compiler
> would still try to use the public API methods, ignoring the hidden friend
> with a correct signature. That's what I tried to illustrate with the links
> from my previous email.

Ah, I see. It's not an ambiguous overload problem because the hidden friend is
not even part of the overload set in the first place. That can be solved by
promoting the function from hidden friend to static member, either as public
or private, depending on the implementer's choice.

That means it can't be used in ADL contexts without scope qualifications, but I
don't see that as an API requirement. The API should be the operators.

> Also, we have inconsistency among our classes, as some of them use two-arg
> static equals(), and others use one-arg non-static equals().

That doesn't seem to be a problem. If we can't make the macros work with
either, then we can simply add another equals to match the one we want,
adapting to the one we don't. That is, we'd probably add a static equals that
calls the non-static one if the latter is already public API and is in the
ABI.

> In my patch[0] I introduce several helper macros that use helper functions
> to provide the actual implementation.
> Since we are talking about "equal()/equals()", let's take
> Q_DECLARE_EQUALITY_COMPARABLE as an example. Omitting all the details,
> and supposing that we use "equals" as a helepr function name, it expands
> into something like this:
>
> friend bool operator==(const MyType , const MyType ) noexcept
> { return equals(lhs, rhs); }
>
> As you can see, we selected the two-arg version of the helper

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-25 Thread Thiago Macieira
On Tuesday, 25 July 2023 01:42:42 PDT Ivan Solovev via Development wrote:
> > And why is that a problem? So long as the proper overload exists, it'll be
> > called. There's only a problem if the overloads are ambiguous.
> 
> The problem is that there might be no "proper" overload, but the compiler
> would still try to use the public API methods, ignoring the hidden friend
> with a correct signature. That's what I tried to illustrate with the links
> from my previous email.

Ah, I see. It's not an ambiguous overload problem because the hidden friend is 
not even part of the overload set in the first place. That can be solved by 
promoting the function from hidden friend to static member, either as public 
or private, depending on the implementer's choice.

That means it can't be used in ADL contexts without scope qualifications, but I 
don't see that as an API requirement. The API should be the operators.

> Also, we have inconsistency among our classes, as some of them use two-arg
> static equals(), and others use one-arg non-static equals().

That doesn't seem to be a problem. If we can't make the macros work with 
either, then we can simply add another equals to match the one we want, 
adapting to the one we don't. That is, we'd probably add a static equals that 
calls the non-static one if the latter is already public API and is in the 
ABI.

> In my patch[0] I introduce several helper macros that use helper functions
> to provide the actual implementation.
> Since we are talking about "equal()/equals()", let's take
> Q_DECLARE_EQUALITY_COMPARABLE as an example. Omitting all the details,
> and supposing that we use "equals" as a helepr function name, it expands
> into something like this:
> 
> friend bool operator==(const MyType , const MyType ) noexcept
> { return equals(lhs, rhs); }
> 
> As you can see, we selected the two-arg version of the helper function.
> This will work without any additional changes for the classes like
> QBluetoothDeviceInfo, which has a private static two-arg equals[1], but
> would fail for classes like QLocale, because it has a one-arg non-static
> equals[2].

As above: let's just add the static bool equals(two arg) to QLocale:

 private:
 QLocale(QLocalePrivate );
 bool equals(const QLocale ) const;
+static bool equals(const QLocale , const QLocale )
+{ return l1.equals(l2); }
 friend class QLocalePrivate;
 friend class QSystemLocale;

The ABI for either function is the same and only differ in mangling. Since 
QLocale is not trivially copyable, we can't implement this with pass-by-value.

> And in any case, none of the existing public APIs would be able to work with
> the generic code. And I keep repeating that it's something that we want to
> provide for our users as building blocks for implementing
> three-way-comparison with C++17.

I disagree with that requirement *because* it's costly. Let them use <=> if 
they want to use generic code.

> The problem with "compare" is the pre-existing QString::compare(), which
> returns an int.

That is not a problem. int is a suitable strong order result type.

> Again, let's consider an example macro from [0].
> Let's take Q_DECLARE_STRONGLY_ORDERED, which expands into all 6 relational
> operators under C++17. I'll consider only operator>() and operator<() here
> for simplicity:
> 
> friend bool operator<(const MyType , const MyType ) noexcept
> { return order(lhs, rhs) == QStrongOrdering::Less; }
> friend bool operator>(const MyType , const MyType ) noexcept
> { return order(lhs, rhs) == QStrongOrdering::Greater; }

I had posted a comment months ago that this definition was wrong, as you'd 
noticed:

> friend bool operator<(const MyType , const MyType ) noexcept
> { return compare(lhs, rhs) < 0; }
> friend bool operator>(const MyType , const MyType ) noexcept
> { return compare(lhs, rhs) > 0; }
> 
> HOWEVER, that will work ONLY for C++17.
> 
> For C++20 we want the Q_DECLARE_STRONGLY_ORDERED marco to simply expand into
> operator<=>():
> 
> friend auto operator<=>(const MyType , const MyType ) noexcept
> { return order(lhs, rhs); }

You forgot the <=> 0 here. Comparing an int with 0 through the spaceship 
operator produces a std::strong_ordering result. And comparing a 
std::strong_ordering with 0 via the spaceship returns itself too.

https://gcc.godbolt.org/z/ebKe8Eb3a

This works for weak_ordering too. For partial_ordering, the case of unordered 
needs to be handled explicitly, so I'd instead require that the called 
function return either std::partial_ordering or QPartialOrdering, nothing 
else.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-25 Thread Ivan Solovev via Development
> Then don't use that as the hidden friend. The public API requirements take
> precedence. So long as the problem is not insurmountable, we should make the
> effort to have a clean API because we'll be stuck with it for the next 10
> years.
>
> > The public methods, in turn, are actually an issue, because the compiler
> > will
> > try to use them instead of a defined hidden friend, even if the number of
> > arguments or their types do not match.
>
> And why is that a problem? So long as the proper overload exists, it'll be
> called. There's only a problem if the overloads are ambiguous.

The problem is that there might be no "proper" overload, but the compiler
would still try to use the public API methods, ignoring the hidden friend
with a correct signature. That's what I tried to illustrate with the links
from my previous email.

Also, we have inconsistency among our classes, as some of them use two-arg 
static
equals(), and others use one-arg non-static equals().

In my patch[0] I introduce several helper macros that use helper functions
to provide the actual implementation.
Since we are talking about "equal()/equals()", let's take
Q_DECLARE_EQUALITY_COMPARABLE as an example. Omitting all the details,
and supposing that we use "equals" as a helepr function name, it expands into
something like this:

friend bool operator==(const MyType , const MyType ) noexcept
{ return equals(lhs, rhs); }

As you can see, we selected the two-arg version of the helper function.
This will work without any additional changes for the classes like
QBluetoothDeviceInfo, which has a private static two-arg equals[1], but would
fail for classes like QLocale, because it has a one-arg non-static equals[2].

I could re-write the macro to use the one-arg version (which does not make
much sense for me), but that would just "reverse" the problem.

And in any case, none of the existing public APIs would be able to work with
the generic code. And I keep repeating that it's something that we want to
provide for our users as building blocks for implementing three-way-comparison
with C++17.

[0]: https://codereview.qt-project.org/c/qt/qtbase/+/475447
[1]: 
https://github.com/qt/qtconnectivity/blob/dev/src/bluetooth/qbluetoothdeviceinfo.h#L233
[2]: https://github.com/qt/qtbase/blob/dev/src/corelib/text/qlocale.h#L1125

> As I said: we should strive for the proper naming.
>
> This also applies to the ordering function be called "compare".

The problem with "compare" is the pre-existing QString::compare(), which
returns an int.
Again, let's consider an example macro from [0].
Let's take Q_DECLARE_STRONGLY_ORDERED, which expands into all 6 relational
operators under C++17. I'll consider only operator>() and operator<() here for 
simplicity:

friend bool operator<(const MyType , const MyType ) noexcept
{ return order(lhs, rhs) == QStrongOrdering::Less; }
friend bool operator>(const MyType , const MyType ) noexcept
{ return order(lhs, rhs) == QStrongOrdering::Greater; }

Here we expect that the order() function returns one of the Q*Ordering types.

I agree that it can be re-written to work with the compare() function
returning an int:

friend bool operator<(const MyType , const MyType ) noexcept
{ return compare(lhs, rhs) < 0; }
friend bool operator>(const MyType , const MyType ) noexcept
{ return compare(lhs, rhs) > 0; }

HOWEVER, that will work ONLY for C++17.

For C++20 we want the Q_DECLARE_STRONGLY_ORDERED marco to simply expand into
operator<=>():

friend auto operator<=>(const MyType , const MyType ) noexcept
{ return order(lhs, rhs); }

Obviously, we want the helper function to remain the same for both C++17 and 
C++20.
I don't see how we can re-use a compare() function returning an int here.

Best regards,

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B

________________
From: Thiago Macieira
Sent: Tuesday, July 25, 2023 2:11 AM
To: development@qt-project.org
Cc: Ivan Solovev
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Monday, 24 July 2023 05:34:58 PDT Ivan Solovev via Development wrote:
> > Why doesn't "equals" work?
> >
> > We've been over this in the code review: our current naming conventions
> > would dictate "equals" even for two arguments, as the most common
> > phrasing is "A equals B" instead of "A and B equal". When you compare
> > things, you always compare at a minimum two of them, so there being two
> > is implied by the act of comparing

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-24 Thread Thiago Macieira
On Monday, 24 July 2023 05:34:58 PDT Ivan Solovev via Development wrote:
> > Why doesn't "equals" work?
> > 
> > We've been over this in the code review: our current naming conventions
> > would dictate "equals" even for two arguments, as the most common
> > phrasing is "A equals B" instead of "A and B equal". When you compare
> > things, you always compare at a minimum two of them, so there being two
> > is implied by the act of comparing anyway. And I don't see why we can't
> > provide both static and non- static members, like QString::compare does
> 
> IIUC, the main problem that Marc has in mind is that the existing class
> member equals() would conflict with the two-arg hidden friend equals(),
> which we would use as a helper for operator==() and operator!=().

Then don't use that as the hidden friend. The public API requirements take 
precedence. So long as the problem is not insurmountable, we should make the 
effort to have a clean API because we'll be stuck with it for the next 10 
years.

> The public methods, in turn, are actually an issue, because the compiler
> will
> try to use them instead of a defined hidden friend, even if the number of
> arguments or their types do not match.

And why is that a problem? So long as the proper overload exists, it'll be 
called. There's only a problem if the overloads are ambiguous.

> Probably this approach would allow us to use "equals()" as a name for the E
> function.
> What do you think?

As I said: we should strive for the proper naming.

This also applies to the ordering function be called "compare".

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering


smime.p7s
Description: S/MIME cryptographic signature
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-07-24 Thread Ivan Solovev via Development
Hi,

let me try to revive the discussion, because we want the C++20 comparison task
to be finished for Qt 6.7.

> > And we have the calling convention:
> > lhs.O(rhs);
> > Qt::O(lhs, rhs); // if you know the type
> >
> > using Qt::O;
> > O(lhs, rhs);
> > . // if you don't
>
> I don't think this is necessary. I would prefer if that were only allowed
> through op<=>.
>
> C++17-constrained users would therefore need to know the types in question,
> know what the "O" function is called and how to call it (static vs non-
> static). And if it isn't public at all, then you're limited to the traditional
> relational operators (op<, op<=, op> and op>=). Mind you, we're not breaking
> those users in any way; we're simply not adding extra API for them.

The whole idea of the C++20 comparison epic is to provide a unified comparison
behavior between C++17 and C++20 *and* to provide the three-way-comparison
features to the Qt users who are still stuck with C++17.

As it was discussed in another mailing threads, we are not planning to demand
C++20 until Qt 6.9 ([0] and [1]), and we will also have one more LTS version
(Qt 6.8) based on C++17.

Considering all the above, I think it's important to give our users the
possibility to implement three-way-comparison in their custom classes.
And here the equal() and order() functions would be the building blocks that
we provide for it. In my opinion, this is the main reason to allows things
like
using Qt::func;
func(lhs, rhs);

[0]: https://lists.qt-project.org/pipermail/development/2023-May/043812.html
[1]: https://lists.qt-project.org/pipermail/development/2023-May/043865.html

Now, regarding the helper function naming:

> Why doesn't "equals" work?
>
> We've been over this in the code review: our current naming conventions would
> dictate "equals" even for two arguments, as the most common phrasing is "A
> equals B" instead of "A and B equal". When you compare things, you always
> compare at a minimum two of them, so there being two is implied by the act of
> comparing anyway. And I don't see why we can't provide both static and non-
> static members, like QString::compare does

IIUC, the main problem that Marc has in mind is that the existing class member
equals() would conflict with the two-arg hidden friend equals(), which we would
use as a helper for operator==() and operator!=().

Grepping through all Qt sources, I see quite a lot of usages of one- or two-arg
equals() methods, however most of them are private.
The private methods are not an issue, because we can use
QT__REMOVED_SINCE to get rid of them.

The public methods, in turn, are actually an issue, because the compiler will
try to use them instead of a defined hidden friend, even if the number of
arguments or their types do not match.
See here for an example:
https://godbolt.org/z/qW6c9dPY8 (two-arg public equals)
https://godbolt.org/z/d19qvxv79 (one-arg public equals)

However, I managed to make it work introducing an extra private static method:
https://godbolt.org/z/3Ycf5Kh1Y (two-arg public equals)
https://godbolt.org/z/nv9jK4eqv (one-arg public equals)

This is not an ideal solution, because, as you can see in the output, the
operator==() explicitly calls the private static method instead of the hidden
friend. However, the generic code also works (this time calling hidden friend,
which forwards to private static).

Probably this approach would allow us to use "equals()" as a name for the E
function.
What do you think?

Best regards,

--

Ivan Solovev
Senior Software Engineer

The Qt Company GmbH
Erich-Thilo-Str. 10
12489 Berlin, Germany
ivan.solo...@qt.io
www.qt.io

Geschäftsführer: Mika Pälsi,
Juha Varelius, Jouni Lintunen
Sitz der Gesellschaft: Berlin,
Registergericht: Amtsgericht
Charlottenburg, HRB 144331 B
________________
From: Development  on behalf of Thiago 
Macieira 
Sent: Wednesday, June 14, 2023 6:16 PM
To: development@qt-project.org 
Subject: Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

On Wednesday, 14 June 2023 01:52:49 PDT Marc Mutz via Development wrote:
> == Why E _and_ O? ==
>
> The reason we need E _and_ O for ordered types instead of just O is that
> O needs to order the lhs w.r.t. the rhs, which generally involves
> looking at all the state of the objects whereas E just needs to find
> _one_ difference to be able to quickly return false. E.g., a container
> can do
>
>  bool E(~~~ lhs, ~~~ rhs) {
>  if (lhs.size() != rhs.size()) return false; // O cannot do this!
>  
>  }
>
> This is a very important optimization (and one reason why L1 string
> literals are going to stay and not be replaced with UTF-8 ones: L1 op
> UTF-16 _c

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-06-14 Thread Thiago Macieira
On Wednesday, 14 June 2023 01:52:49 PDT Marc Mutz via Development wrote:
> == Why E _and_ O? ==
> 
> The reason we need E _and_ O for ordered types instead of just O is that
> O needs to order the lhs w.r.t. the rhs, which generally involves
> looking at all the state of the objects whereas E just needs to find
> _one_ difference to be able to quickly return false. E.g., a container
> can do
> 
>  bool E(~~~ lhs, ~~~ rhs) {
>  if (lhs.size() != rhs.size()) return false; // O cannot do this!
>  
>  }
> 
> This is a very important optimization (and one reason why L1 string
> literals are going to stay and not be replaced with UTF-8 ones: L1 op
> UTF-16 _can_ use the size() short-cut while UTF-8 op UTF-16 cannot).

It's also why glibc added __memcmpeq and GCC and Clang can generate a call to 
that. Same reason why I added QtPrivate::equalStrings() different from 
QtPrivate::compareStrings() (internally they call ucstreq and ucstrcmp, 
respectively).

> == Can E be spelled op==? ==
> 
> It could. However, op== cannot have extra arguments and we have at least
> one use-case where E might have an additional argument: case-insensitive
> string comparisons. We currently have no (public) API to express op==,
> but case-insensitively. The closest we have is QString::compare(), but
> that is an O, so it cannot use the size() mismatch shortcut, assuming
> it's valid for case-insensitive string comparison (it is for L1, dunno
> about UTF-16).

Hmm... the facts are correct but I don't think that leads to the conclusion. 
The whole objective here is to provide op== anyway, so the fact that some 
classes have this implemented in another method that can do more should be 
irrelevant. For those, this op== can be inline and call the out-of-line 
function that does the relevant work.

> There's also the situation where (cheap!) implicit conversions allow one
> E to backfill several different op== (which, being hidden friends, don't
> participate in implicit conversions themselves). If E is spelled op==,
> what would the macros use to implement op==? It would be up to the class
> author to supply sufficiently-many op== in the correct form. We don't
> want that. We want all op== to be generated from the macros so we have
> central control over their generation (providing reversed operators in
> C++17, getting the signatures right, noexcept-ness, hidden-friend-ness,
> ...).

They can be exceptions and written manually.

However, I do not object to having the op== be an inline hidden friend, 
calling a private static noexcept equality comparator function (whether that's 
inline or not, taking extra arguments or not). In fact, I like that, purely on 
stylistic reasons.

> == O as public API ==
>
> In C++20, O would be spelled op<=>, but this is not possible in C++17,
> so O needs to be an actual named function, not an operator. The
> question, and it's a rhetorical one, then becomes: should O be public
> API, and the (rhetorical) answer is "yes, because C++17 users will want
> to be able to access O in C++17 projects, too (in C++20, they could call
> op<=>)". This includes Qt's own implementation of O's.

Side note: I think we should start compiling Qt with C++20 right now, for all 
compilers that support it, with no possibility for the user to turn that off. 
There is C++20 functionality we could use in our implementations that don't 
affect ABI and don't constrain C++17 users. And I also don't object to 
providing C++20-only features, discussed on a case-by-case basis.

> Applied to our situation, this means:
> 
> - each (orderable) class supplies O as a hidden friend
> - may supply it as a (non-static) member function

"At a minimum" as a hidden friend. It may be public API, like 
QString::compare(), whether static or non-static.

> And we have the calling convention:
> lhs.O(rhs);
> Qt::O(lhs, rhs); // if you know the type
> 
> using Qt::O;
> O(lhs, rhs);
> . // if you don't

I don't think this is necessary. I would prefer if that were only allowed 
through op<=>.

C++17-constrained users would therefore need to know the types in question, 
know what the "O" function is called and how to call it (static vs non-
static). And if it isn't public at all, then you're limited to the traditional 
relational operators (op<, op<=, op> and op>=). Mind you, we're not breaking 
those users in any way; we're simply not adding extra API for them.

Paraphrasing you about a decade ago, "C++17 costs more".

> This leads to the finding that O (and, depending on the outcome of the
> first two Open Questions) E cannot be named like static binary functions
> in existing classes, as, even if they are semantically compatible,
> they're syntactically incompatible.
>
> That objectively rules out "compare" for O and "equals" for E.

Conclusion invalidated due to premise rejected. I couldn't follow your logic 
anyway, but since the premise was no longer applicable, I didn't try very 
hard.

> == 

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-06-14 Thread Edward Welbourne via Development
Marc Mutz (14 June 2023 10:52) wrote:
> == Naming E ==
>
> So far, we've been using equal(). equals() doesn't work for technical
> reasons, but while it'd work as a member function lhs.equals(rhs),
> it's also kinda wrong if the function is taking two arguments
> (equals(lhs, rhs), but there are _two_ objects). So equal() as the
> plural form or equals() makes sense.

No, it really doesn't (but it's illuminating to finally see why you
thought it did).

Sure, if we have two objects whose masses together equal that of a
third, you get "equal" as the plural of "equals" but it's *still
transitive* and its "those two equal this one".  You can stretch to
"these two equal one another" but it's severely contrived to do so; you
would say "these two are equal".  Besides, if you don't like areEqual(),
you're really not going to welcome equalOneAnother().

I've no objection to eq() and cmp(), though,

Eddy.
-- 
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2023-06-14 Thread Marc Mutz via Development
On 03.11.22 10:40, Marc Mutz via Development wrote:
> TL;DR: provide named functions for the minimal set of op== and op<=>
> we'd have to write in C++20, then use macros to turn these into op==,
> op!=, op<, op>, op<=, op>= for C++17 builds and op== and op<=> for C++20
> builds.

This part somehow became lost and kinda made the whole feature miss the 
6.6 train, so let me expand on it a bit, and collect open questions 
(marked with → below):

We want the implementation of these relational operators be as close as 
possible to the way C++20 will work: There, you implement op== and op<=> 
and the compiler synthesizes everything else (cf. parent message for 
details). So we need one function E backing op== and, for ordered types, 
another function O backing op<=>.

== Why E _and_ O? ==

The reason we need E _and_ O for ordered types instead of just O is that 
O needs to order the lhs w.r.t. the rhs, which generally involves 
looking at all the state of the objects whereas E just needs to find 
_one_ difference to be able to quickly return false. E.g., a container 
can do

 bool E(~~~ lhs, ~~~ rhs) {
 if (lhs.size() != rhs.size()) return false; // O cannot do this!
 
 }

This is a very important optimization (and one reason why L1 string 
literals are going to stay and not be replaced with UTF-8 ones: L1 op 
UTF-16 _can_ use the size() short-cut while UTF-8 op UTF-16 cannot).

== Can E be spelled op==? ==

It could. However, op== cannot have extra arguments and we have at least 
one use-case where E might have an additional argument: case-insensitive 
string comparisons. We currently have no (public) API to express op==, 
but case-insensitively. The closest we have is QString::compare(), but 
that is an O, so it cannot use the size() mismatch shortcut, assuming 
it's valid for case-insensitive string comparison (it is for L1, dunno 
about UTF-16).

So there's a certain appeal in using E as a way to consistently spell 
"op== with extra arguments". We could, e.g. do E(lhs, rhs, 
Qt::FuzzyComparison) for anything involving FP.

There's also the situation where (cheap!) implicit conversions allow one 
E to backfill several different op== (which, being hidden friends, don't 
participate in implicit conversions themselves). If E is spelled op==, 
what would the macros use to implement op==? It would be up to the class 
author to supply sufficiently-many op== in the correct form. We don't 
want that. We want all op== to be generated from the macros so we have 
central control over their generation (providing reversed operators in 
C++17, getting the signatures right, noexcept-ness, hidden-friend-ness, 
...).

So I would require new information to accept anything than a "no" here:

→ Semi-Open question 1:
Should E be spelled op==?

My take is no.

→ Open question 2:
Should E exist for all types, as a "concept name" for "op== with 
parameters", or should we leave that, as it is now, on type-by-type 
basis to each class author individually?

My take is that yes, it should exist as a "concept name". I added 
qStringsEqual() in 5.10 as public API when adding QStringView, but it 
was relegated to private API before the release. When class authors are 
given the option to accept parameters for equality comparison, they will 
find novel ways to use it (like Qt::Fuzzy).

== O as public API ==

In C++20, O would be spelled op<=>, but this is not possible in C++17, 
so O needs to be an actual named function, not an operator. The 
question, and it's a rhetorical one, then becomes: should O be public 
API, and the (rhetorical) answer is "yes, because C++17 users will want 
to be able to access O in C++17 projects, too (in C++20, they could call 
op<=>)". This includes Qt's own implementation of O's.

The gold standard for named operators in C++ is to have the 
implementation as a hidden friend (think swap()), possibly a member 
function (lhs.swap(rhs)), a (namespaced) fallback version for built-in 
types (std::swap(int, int)) and a calling convention that takes this 
into account:

lhs.swap(rhs);
// or
std::swap(lhs, rhs); // if you know decltype(lhs), ...

using std::swap;
swap(lhs, rhs);
// or
std::ranges::swap(lhs, rhs); // ... if you don't.

Applied to our situation, this means:

- each (orderable) class supplies O as a hidden friend
- may supply it as a (non-static) member function
- Qt provides an implementation for built-in types in a namespace (we 
only have 'Qt').

And we have the calling convention:

lhs.O(rhs);
Qt::O(lhs, rhs); // if you know the type

using Qt::O;
O(lhs, rhs);
O_as_CPO(lhs, rhs); // if you don't

O_as_CPO is to O what std::ranges::swap is to swapping: an ADL-enabled 
version that allows to skip the using Qt::O/using std::swap;

The same would be applicable to E if Open Question 1 ends up resolved as 
no and Open Question 2 as "yes, named concept".

This leads to the finding that O (and, depending on the outcome of the 
first 

Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-07 Thread Edward Welbourne via Development
On 04.11.22 12:13, Ulf Hermann via Development wrote:
>> One thing I haven't understood about the ordering problem is why we
>> cannot just define our "invalid" values to always be < any valid one and
>> equal to other invalid ones. This way we get at least weak ordering for
>> all our types and we're done.

Marc Mutz via Development (4 November 2022 16:15)
> That's what we're currently doing, yes. At least for QDateTime.

One factor in why I think partial order is probably a good choice is
that invalid QDateTimes are a bit more complicated than, say, null
QStrings; there is a null QDateTime, but you can also get an invalid one
by asking for a time that doesn't exist in the zone (overtly for spec =
TimeZone, implicitly for spec = LocalTime) in use, when folk moved their
clocks forward over that time in the given zone, typically in spring at
the start of DST.  These QDateTime instances, although invalid, do have
a toMSecsSinceEpoch() that's suitable to passing to
fromMSecsSinceEpoch() to reconstruct a valid date-time that's not what
you originally asked for but is close by.  See [0] for my attempt to do
better than that kludge.

[0] https://codereview.qt-project.org/c/qt/qtbase/+/308729/25

> For QString, we have that isNull() compares equal to empty.

Which makes a fair amount of sense, IMO.
Default-constructed string is empty.

> ... that prompted
> me to remember QOperatingSystemVersion, where we really, genuinely
> have several sets of values where elements from different sets are not
> ordered (Win10  There, partial_ordering is consistent with the current implementation.

Good example.

> We don't _need_ to make invalid values unordered, but it would be the
> mathematically correct thing to do.

... in some cases, at least.  For containers, like QString,
null-is-empty makes perfect mathematical sense, for example; the empty
set is the "null" set (and relation, and function), in so many senses.
Indeed, IIRC, the first teacher to introduce me to it used a
slashed-zero called "null" to denote it.

> We removed QVariant::op< because of these problems. partial_ordering
> would allow [us] to bring it back.

Albeit "whether we *should*" remains a separate story.

>> There may be types where existing operator< work differently (*cough*
>> QTypeRevision), but that just means we need to emulate that same
>> behavior with the new operators.

> Without having looked at QTypeRevision, I agree in general.

Certainly in the first instance we should match existing behaviour as
closely as possible with the new operators; but partial ordering does
present (once we're fully migrated to C++20) a new option that may be a
good choice for some types.  I don't advocate a blanket "do this
everywhere"; but there may well be types for which it makes sense.

>> Indeed the NaN behavior has always been a pain to deal with every time
>> I've encountered it. If we have a chance to avoid it, we should.
>>
>> What is the downside of such an approach?

> The (potential) downside is that it's arbitrary and classes might behave
> inconsistently (one sorts invalid before valid ones, the other vice
> versa). It may also be a bit more work to document (unless we choose not
> to mention that little detail). Or we can't reap any future tool support
> that might be developed for partial_ordering (sanitizers, etc).

The NaN behaviour is a necessary escape from worse surprises; for
example, "if x < 0 and y < 0, then x * y > 0" - except that if you make
NaN < 0 that'll fail.  Of course, having the NaN drop into the else
branch of an if (x < 0) is apt to have it mistakenly presumed to be >=
0, when it also isn't that.  Still, with the language now actually
supporting partial order, we get the option of using it and at least
giving diligent programmers the chance to handle such cases gracefully'
and by overtly making some orderings partial, alert them to the need to.

The question remains: for which of our types will it actually make sense
to have a partial ordering ?  I trust those closest to the code to have
a clue, in each instance.

Eddy.
___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-04 Thread Marc Mutz via Development
Hi Ulf,

On 04.11.22 12:13, Ulf Hermann via Development wrote:
> One thing I haven't understood about the ordering problem is why we 
> cannot just define our "invalid" values to always be < any valid one and 
> equal to other invalid ones. This way we get at least weak ordering for 
> all our types and we're done.

That's what we're currently doing, yes. At least for QDateTime. For 
QString, we have that isNull() compares equal to empty. Each class has 
it's own semantics. I'll have a look at QTypeRevision, but that prompted 
me to remember QOperatingSystemVersion, where we really, genuinely have 
several sets of values where elements from different sets are not 
ordered (Win10  There may be types where existing operator< work differently (*cough* 
> QTypeRevision), but that just means we need to emulate that same 
> behavior with the new operators.

Without having looked at QTypeRevision, I agree in general.

> Indeed the NaN behavior has always been a pain to deal with every time 
> I've encountered it. If we have a chance to avoid it, we should.
> 
> What is the downside of such an approach?

The (potential) downside is that it's arbitrary and classes might behave 
inconsistently (one sorts invalid before valid ones, the other vice 
versa). It may also be a bit more work to document (unless we choose not 
to mention that little detail). Or we can't reap any future tool support 
that might be developed for partial_ordering (sanitizers, etc).

Overall, I don't feel strongly about it (no pun intended). From the 
ongoing discussion more and more examples pop up, though, where 
partial_ordering would be a really good idea (QVariant, QOSVersion, 
QTypeRevision?), and if those definite use-cases make people more 
familiar with partial_ordering, maybe invalid-as-unorderable would also 
come to be felt as more natural.

Thanks,
Marc

___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-04 Thread Ulf Hermann via Development

Hi,

One thing I haven't understood about the ordering problem is why we 
cannot just define our "invalid" values to always be < any valid one and 
equal to other invalid ones. This way we get at least weak ordering for 
all our types and we're done.


There may be types where existing operator< work differently (*cough* 
QTypeRevision), but that just means we need to emulate that same 
behavior with the new operators.


Indeed the NaN behavior has always been a pain to deal with every time 
I've encountered it. If we have a chance to avoid it, we should.


What is the downside of such an approach?

best regards,
Ulf
___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-04 Thread Edward Welbourne via Development
On Thursday, 3 November 2022 09:48:49 PDT Marc Mutz via Development wrote:
>>> Here, too, I feel lost. I'm struggling to see what a NIH
>>> std::partial_ordering w/o the weak and strong counterparts and w/o
>>> op<=> language support could achieve, except another vocabulary type
>>> mismatch.  Can you elaborate?

On 03.11.22 18:38, Thiago Macieira wrote:
>> We can use it until we can depend on C++20. Like QSpan, that's why it's 
>> there.

Marc Mutz (4 November 2022 11:22)
> The difference is that QSpan vs. std::span doesn't create an impedance
> mismatch. QPartialOrdering vs. std::partial_ordering does, esp. since
> QPartialOrdering lacks an implicit conversion to/from
> std::partial_ordering, and the member names are different.

Since my comments on QDateTime are implicated here, I should note that -
since it would be a behaviour change - an initial transition to a weak
ordering that preserves invalid < valid could perfectly well suffice
until we *do* transition to C++20 and *can* use std::partial_order, at
which point I do think it would make sense to change our types with
invalid (but supported) null-forms to make them incomparable, ideally
all at the same time.

> With the exception of qfloat32, I'm not aware of any Qt type that
> would exhibit partial ordering semantics atm.

I take it you mean qfloat16, whose NaN is incomparable,

Eddy.
___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-04 Thread Marc Mutz via Development
Hi Thiago,

On 03.11.22 18:38, Thiago Macieira wrote:
> On Thursday, 3 November 2022 09:48:49 PDT Marc Mutz via Development wrote:
>> On 03.11.22 16:17, Thiago Macieira wrote:
>>> For some classes, we could postpone changing anything until C++20 is
>>> required.
>> You lost me there. Why do you think so? Because of the sentence above?
>> Requiring C++20 won't be a BC break, so we'd still have all the old
>> exported relational operators to QT_REMOVED_SINCE.
> 
> A simple question of code readability. If it's not that important and it makes
> the code significantly uglier, we can simply postpone until it's not ugly.

Yes, we could postpone, but I feel that would be a disservice to both us and 
our users.

To us, because we simply don't have the bandwidth to do all C++20 
changes at once, so we need to select which ones we can do before we 
require C++20, and this is one of them.

To our users, because we currently don't have a clue whether our 
relational operators are free of C++20 ambiguities. We _think_ we caught 
them all, but we don't have a C++20 build on the CI, yet to know for 
sure, and,even if we did, we typically don't have the test coverage to 
test all combinations (incl. const/mutable and l/rvalue). Ambiguities 
are detected at call time, not declaration time, so we need exhaustive 
checking, anyway. I believe it's better to fix this issue before we 
require users to use C++20, forcing them into exposing our remaining 
bugs. And to fix them consistently. A user doesn't care whether his 
C++20 build breaks because of QJsonValue or QWaylandBufferRef.

>>> Meanwhile, we have qcompare.h.
>>
>> Here, too, I feel lost. I'm struggling to see what a NIH
>> std::partial_ordering w/o the weak and strong counterparts and w/o op<=>
>> language support could achieve, except another vocabulary type mismatch.
>> Can you elaborate?
> 
> We can use it until we can depend on C++20. Like QSpan, that's why it's there.

The difference is that QSpan vs. std::span doesn't create an impedance 
mismatch. QPartialOrdering vs. std::partial_ordering does, esp. since 
QPartialOrdering lacks an implicit conversion to/from 
std::partial_ordering, and the member names are different.

> Or the methods can simply return int, like I intended in QCborValue.

That's what I was thinking, yes.

>> Meanwhile, in a Jira comment, Eddy discovered a potential problem with
>> partial_ordering::unordered: we have a lot of types that have
>> std::optional folded into them (isNull/isValid) and, if they're ordered,
>> they need to have decided on a total order, ie. incl. for invalid/null
>> ones (QDateTime sorts invalid before valid e.g.). These types' op<=>
>> could now return unordered for invalid values, but that would change the
>> semantics of the op< derived from it vis a vis the existing op<.
> 
> What's the recommendation? Create a total order where null < empty < any non-
> empty, or use partial ordering?

For new classes, knowing what I know now, I'd use partial ordering 
(though I'd also ask to consider avoiding baking in optional<> semantics 
to elegantly side-step the issue). For existing classes, we need to keep 
the total order they most likely are currently using. With the exception 
of qfloat32, I'm not aware of any Qt type that would exhibit partial 
ordering semantics atm. Whether we then switch to a partial order come 
Qt 7 is a different question. I would make that contingent on how 
support for partial_ordering in the wider C++ ecosystem in coming along.

Thanks,
Marc

___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-03 Thread Thiago Macieira
On Thursday, 3 November 2022 09:48:49 PDT Marc Mutz via Development wrote:
> Hi Thiago,
> 
> On 03.11.22 16:17, Thiago Macieira wrote:
> > the devil will be in the details because of QT_REMOVED_SINCE.
> 
> What, specifically, are you thinking about here? For the sketched
> approach to work, no new relational operator must be exported, because
> we need to keep BC between C++17 and C++20 builds. If existing ones are,
> we'll need to QT_REMOVED_SINCE them. Where's the problem?

Nothing specific. It could be nothing, it could be simple ugliness that / code 
readability, or there may be some classes we can't move the operators away for 
at all: there was one case we couldn't remove / move away because the method 
was inline and was used by QtCore itself. We won't know until we try.

> > For some classes, we could postpone changing anything until C++20 is
> > required.
> You lost me there. Why do you think so? Because of the sentence above?
> Requiring C++20 won't be a BC break, so we'd still have all the old
> exported relational operators to QT_REMOVED_SINCE.

A simple question of code readability. If it's not that important and it makes 
the code significantly uglier, we can simply postpone until it's not ugly.

> > Meanwhile, we have qcompare.h.
> 
> Here, too, I feel lost. I'm struggling to see what a NIH
> std::partial_ordering w/o the weak and strong counterparts and w/o op<=>
> language support could achieve, except another vocabulary type mismatch.
> Can you elaborate?

We can use it until we can depend on C++20. Like QSpan, that's why it's there.

Or the methods can simply return int, like I intended in QCborValue.

> Meanwhile, in a Jira comment, Eddy discovered a potential problem with
> partial_ordering::unordered: we have a lot of types that have
> std::optional folded into them (isNull/isValid) and, if they're ordered,
> they need to have decided on a total order, ie. incl. for invalid/null
> ones (QDateTime sorts invalid before valid e.g.). These types' op<=>
> could now return unordered for invalid values, but that would change the
> semantics of the op< derived from it vis a vis the existing op<.

What's the recommendation? Create a total order where null < empty < any non-
empty, or use partial ordering?

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering



___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-03 Thread Marc Mutz via Development
Hi Thiago,

On 03.11.22 16:17, Thiago Macieira wrote:
> the devil will be in the details because of QT_REMOVED_SINCE.

What, specifically, are you thinking about here? For the sketched 
approach to work, no new relational operator must be exported, because 
we need to keep BC between C++17 and C++20 builds. If existing ones are, 
we'll need to QT_REMOVED_SINCE them. Where's the problem?

> For some classes, we could postpone changing anything until C++20 is required.

You lost me there. Why do you think so? Because of the sentence above? 
Requiring C++20 won't be a BC break, so we'd still have all the old 
exported relational operators to QT_REMOVED_SINCE.

> Meanwhile, we have qcompare.h.

Here, too, I feel lost. I'm struggling to see what a NIH 
std::partial_ordering w/o the weak and strong counterparts and w/o op<=> 
language support could achieve, except another vocabulary type mismatch. 
Can you elaborate?



Meanwhile, in a Jira comment, Eddy discovered a potential problem with 
partial_ordering::unordered: we have a lot of types that have 
std::optional folded into them (isNull/isValid) and, if they're ordered, 
they need to have decided on a total order, ie. incl. for invalid/null 
ones (QDateTime sorts invalid before valid e.g.). These types' op<=> 
could now return unordered for invalid values, but that would change the 
semantics of the op< derived from it vis a vis the existing op<.

I'm also fearful that Qt might be the only library that makes such 
widespread use of partial_ordering::unordered, because it's the only 
library that bakes optional semantics into so many of its types.

So, for new classes, by all means, use partial_ordering, but for 
existing types, I'd err on the side of caution and keep the total 
ordering for now and see how the greater C++ ecosystem's support for 
partial_ordering::unordered evolves. After all, unordered just means NaN 
semantics, and I've never heard of someone that likes that behaviour:

   NaN == NaN is false
   NaN != NaN is false
   NaN < NaN is false
   ...

Thanks,
Marc

___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


Re: [Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-03 Thread Thiago Macieira
On Thursday, 3 November 2022 02:40:51 PDT Marc Mutz via Development wrote:
> This would be much easier done with an ABI break, but we have the tools
> (QT_REMOVED_SINCE) now to deal with this already now.
> 
> If we also make all these operators hidden friends
> (https://bugreports.qt.io/browse/QTBUG-87973), then we at the same time
> improve the user experience by removing overly-verbose error messages
> when something goes wrong. If we do this, though, some incidental
> comparisons that rely on implicit conversions will stop working. This is
> a good thing, IMO, because it forces us to provide (and therefore
> document) these operators explicitly.
> 
> The process will also force us to (at least mentally) assign level
> numbers to heterogeneously-comparable classes. This might run into
> problems (such as QTBUG-108136), but is overall a good thing.
> 
> Opinions? Comments?

This one is also a nice improvement and I'd welcome it, but the devil will be 
in the details because of QT_REMOVED_SINCE. For some classes, we could 
postpone changing anything until C++20 is required. Meanwhile, we have 
qcompare.h.

-- 
Thiago Macieira - thiago.macieira (AT) intel.com
  Cloud Software Architect - Intel DCAI Cloud Engineering



___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development


[Development] C++20 comparisons @ Qt (was: Re: C++20 @ Qt)

2022-11-03 Thread Marc Mutz via Development
Hi,

C++20 changed the semantics of relational operators quite a bit, and it 
affects all Qt classes that are equality-comparable and/or ordered.

In the following, A and B are types and a and b are objects of type A 
and B, resp.

First, the compiler will now synthesize missing operators from existing 
ones. So a C++20 program only needs to provide op==(A, B) and the 
compiler can use this to satisfy requests for all of these:

- a == b (obviously)
- a != b (by inverting the result)
- b == a (by reversing the arguments)
- b != a (by doing both)

In turn, this can now cause ambiguities (ie. hard compile errors) when 
there's an asymmetry between user-provided operators and the 
compiler-synthesized ones. At the very least, we need to fix these for 
our C++20 users and one open question is whether we pick these into 
older branches and if so, how far back. I know projects that were very 
close to using C++20 together with Qt 5 a year or so ago.

One can even now = default the equality operator. Then the compiler 
creates one based on for member-wise equality. If all such members have 
an = default'ed equality operator, and with a few other other 
requirements, the type in question has Strong Structural Equality, and 
thus can be used as arguments to non-type template parameters (NTTP). 
QFlags and QFixed are examples where this might come in handy. There are 
probably others, too.

For ordered types, C++20 introduces a new relational operator, 
affectionately called the spaceship operator <=>. It basically returns 
-1, 0, 1 based on whether the lhs is <, ==, > the rhs (think strcmp). 
However, it doesn't return int, but one of three scoped enums:

- partial_ordering (allows incomparable elements, think NaN op NaN, if 
we could turn back time and rewrite IEEE754)
- weak_ordering (allows equivalent, but non-equal elements, think qstricmp)
- strong_ordering (requires a trichotomy (exactly one of <, ==, > is 
true for every pair or lhs, rhs and there's no public API that, when ==, 
allows to tell a difference between the types (addressof is allowed to 
differ)

 From this operator,, the compiler can synthesize all of <, >, <=, >=. But 
users 
can also call it manually.

So, not only must we provide op <=> for all of our ordered types, we 
must also decide in which of the three categories (partial, weak, 
strong) each comparison falls. And not just for homogeneous relations (a 
op a), but heterogeneous ones, too (a op b).

I think this presents us with an excellent opportunity to re-design our 
currently-ad-hoc way of dealing with relational operators, which all too 
often are just documented as functions (documenting individual op== op!= 
for all combinations of {QRect,QRectF} × {QRect,QRectF} instead of as 
properties of the type (QRect: "QRect is equality-comparable with itself 
and QRectF", QRectF: "QRectF is equality-comparable with itself and QRect").

I think this would improve the user documentation immensely, esp. if we 
find a way to conveniently say why some relation is _not_ provided, too 
("QRect is not ordered, because any ordering would be arbitrary and not 
natural") and = delete the corresponding operators:

// QRect:
friend void operator<=>(QRect, QRect) = delete;
// QRectF:
friend void operator<=>(QRectF, QRectF) = delete;
friend void operator<=>(QRectF, QRect) = delete;

I have drafted a proposal for how to go about the change here: 
https://bugreports.qt.io/browse/QTBUG-103757?focusedCommentId=671497#comment-671497

TL;DR: provide named functions for the minimal set of op== and op<=> 
we'd have to write in C++20, then use macros to turn these into op==, 
op!=, op<, op>, op<=, op>= for C++17 builds and op== and op<=> for C++20 
builds.

This would be much easier done with an ABI break, but we have the tools 
(QT_REMOVED_SINCE) now to deal with this already now.

If we also make all these operators hidden friends 
(https://bugreports.qt.io/browse/QTBUG-87973), then we at the same time 
improve the user experience by removing overly-verbose error messages 
when something goes wrong. If we do this, though, some incidental 
comparisons that rely on implicit conversions will stop working. This is 
a good thing, IMO, because it forces us to provide (and therefore 
document) these operators explicitly.

The process will also force us to (at least mentally) assign level 
numbers to heterogeneously-comparable classes. This might run into 
problems (such as QTBUG-108136), but is overall a good thing.

Opinions? Comments?

Thanks,
Marc

References:
- https://bugreports.qt.io/browse/QTBUG-103757
- https://bugreports.qt.io/browse/QTBUG-104110
- https://bugreports.qt.io/browse/QTBUG-104114
- https://bugreports.qt.io/browse/QTBUG-104108
- https://en.cppreference.com/w/cpp/header/compare
- https://bugreports.qt.io/browse/QTBUG-104180

___
Development mailing list
Development@qt-project.org
https://lists.qt-project.org/listinfo/development