[Development] Proposing to change https://wiki.qt.io/API_Design_Principles#Enums_in_classes to require scoped enums

Marc Mutz marc.mutz at qt.io
Thu Jan 16 11:56:50 CET 2025


Hi,

Groundhog Day...

Like every API review, so also in 6.9, we have the discussions between 
proponents of scoped vs. unscoped enums in class scope.

Can we, please, settle this by strengthening the wording of 
https://wiki.qt.io/API_Design_Principles#Enums_in_classes to something 
that requires scoped enums?

I believe everyone agrees that there are _technical_ reasons to prefer 
scoped enums: no implicit conversion to underlying_type, defined 
underlying type even if not explicitly given, etc.

Which leaves the stylistic issue. But I believe the argument

 > Using scoped enums in this case would add redundant line noise:

is a very _un_-Qt-ish one. In Qt, we believe that brevity does not 
automatically equal readability¹, and the more explicit

 > if (point.state() == TouchPoint::State::Pressed)

is more (but certainly not less) readable than

 > if (state() == TouchPoint::Pressed)

Even as the author if the code, the IDE will throw all enumerators of 
unscoped enums into the autocompletion set, and while it may be said to 
be a tooling problem, the fact that for scoped enums I'm first presented 
with the enum, and only then with the enum's enumerators is a powerful 
help. In fact, I find myself using the optional scoped mode for unscoped 
enums more and more, for this very reason.

So, I think we should ban the use of unscoped (new) enums, with only one 
exception: if C compat is required.

If the enum is a complete representation of the class (e.g. 
QJsonParseError::ParseError), I concur that it makes little sense to 
require QJsonParse::ParseError::FooBar.²

But the implicit conversions of unscoped enums are still unwanted!

Even there, we therefore might want to require scoped enums, but then, 
in the class, say `using enum E;` to import the names into class scope, 
gaining the shortcut notation while keeping the disabled implicit 
conversion to underlying type. Alas, that's a C++20 feature, so while I 
think that's the way forward, for the time being, I'm hesitant to 
require writing manual forwarders as static constexpr class variables 
(though, for small enums of a handful of entries, I'd say "do it").

In Qt 7, though, we should definitely make all old enums scoped, too 
(with (hopefully deprecate-able) using enum E for SC). We might actually 
be able to do this in Qt 6 if we can figure out reliably what the 
unscoped enum's underlying type was (which, unfortunately, can, and 
does, differ from platform to platform).

¹ to wit, Q3Slider s(0, 100, 10, 20, 50, true, false, "slider") vs. 
Q4Slider s(Qt::Horizontal); set.setRange(0, 100); ...

² Note, though, how QGrpcStatus 
(https://doc.qt.io/qt-6/qgrpcstatus.html) elegantly evades the issue by 
putting the enum at namespace scope.

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at qt.io> (he/his)
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


More information about the Development mailing list