[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:58:01 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