6 ms·
Enum class improvements for C++17, C++20 and C++23
- deleted 2y ago[deleted]
- fouronnes3 2y agoUnion, inheritance, dynamic_cast, enum class, std::variant... when all we needed all along was proper sum types.
- searealist 2y agoSum types do not replace all the things you listed. Even Rust has different concepts for many of those.
- tialaramex 2y agoI don't think they're complaining that Sum types are equivalent to any or all of those things, but rather that what they wanted was Sum types and C++ has given them all this other stuff claiming it will solve their problem, instead of a Sum type which does solve the problem. If what I need is a bookshelf then it's true that a wardrobe, a cardboard box, a Kindle, and a shredder are all different things and a bookshelf would not substitute for any of them, but giving me the wardrobe, cardboard box, Kindle and shredder doesn't solve my problem, I needed a bookshelf.
- searealist 2y agoIt makes no sense to mention dyanmic_cast or inheritance (clearly referencing virtual functions here) when languages with sum types also have equivalents. It just shows a misunderstanding of how these features are used. I don't think I've ever seen an analogy contribute to a discussion, and yours is no exception.
- maattdd 2y agoInheritance (the subtyping part of it) is considered the OOP way to write sum type. sum Expr { Int; Add(Int,Int) } VS class Expr { } class Add extends Expr { Expr left; Expr right; }
- searealist 2y agoThat's not C++.
- maattdd 2y agoAny reader who comment here hopefully has enough knowledge to understand the implied C++. struct Add {} std::variant<Add, int> Expr; OR class Expr {} class Add : Expr {}
- searealist 2y agoI dont think you have ever seriously used c++.
- deleted 2y ago[deleted]
- gpderetta 2y agoThe expression problem enters the room.
- OvbiousError 2y agoYou should probably look up what a sum type is, it has nothing to do with summations. Your example doesn't contain a sum type. A C++ example: std:variant<int,std::string> sum_type_instance = 5;
- maattdd 2y agoMy sum type example is exactly this (but I didn't use C++ std::variant<> syntax to not confuse the reader). The most common example of a sum type is the "Expression problem" - please read some literature before commenting on a topic. (Btw, it's called sum type for a reason: summation. The cardinality of the sum type is the sum of the cardinality of its variants)
- tialaramex 2y agoMy guess currently is that C++ 29 will get some sort of pattern matching. It's too big a feature to board the C++ 26 train in autumn 2024 and there's nowhere close to consensus on how it should work or how it's spelled yet. So, assume C++ 29 has pattern matching. That causes people to attempt various idiomatic constructions from languages which always had pattern matching, and of course they're all rather awkward in C++. I think that realisation might point towards an actual language sum type, possibly via abortive attempts to "fix" matching and/or some of the pseudo-sum types provided by the C++ stdlib. So then you'd expect proposals in C++ 32 or C++ 35.
- gpderetta 2y agoThere are two competing pattern matching proposals, hopefully they'll converge soon.
- tialaramex 2y agoIn the last mailing Bjarne decided to offer his own syntax P3332, so that makes three.
- westurner 2y agoSpeaking of enums, what's a better serialization framework for C++ like Serde in Rust, and then what about Linked Data support and of course also form validation. Linked Data triples have (subject, predicate, object) and quads have (graph, subject, predicate, object). RDF has URIs for all Subjects and Predicates. RDF Objects may be URIs or literal values like xsd:string, xsd:float64, xsd:int (32bit signed value), xsd:integer, xsd:long, xsd:time, xsd:dateTime, xsd:duration. RDFS then defines Classes and Properties, identified by string URIs. How best to get from an Enum with (type,attr, {range of values}) to an rdfs:range definition in a schema with a URI prefix? Python has dataclasses which is newer than attrs, but serde also emits Python pickles
- beached_whale 2y agore Serde: If you want JSON, https://github.com/beached/daw_json_link https://github.com/beached/daw_json_link is about as close as we can get. It interop's well with the reflection(or like) libraries such as Boost Describe or Boost PFR and will work well with std reflection when it is available.
- westurner 2y agoProbably not too much work to add and then also build a JSONLD @context from all of the ~ message structs. :Thing > https://schema.org/name https://schema.org/name , :URL , :identifier and subclasses Thing > Intangible > Enumeration: https://schema.org/Enumeration https://schema.org/Enumeration
- beached_whale 2y agoAdding reflection will be simple and backwards compatible with existing code as it would only come into play when someone hasn't manually mapped a type. This leaves the cases where reflection doesn't work(private member variables) still workable too. Haven't looked at JSONLD much, but it seems like it could be added but would be a library above I think. Extracting the mappings is already doable and is done in the JSON Schema export.
- James_K 2y ago> C++20 introduced the `using enum` syntax, which enhances the usability of enums Out of context, this is a very funny thing to say.
- jeffbee 2y agoOdd that it says auto value = std::to_underlying(p); // C++23 is "more expressive" than uint8_t value = static_cast<uint8_t>(Permissions::Read); The latter seems clearly more expressive, not less. You could tighten it up a bit by using auto on the LHS instead of the redundant uint8_t. In the former I don't know what's going on and I have to go read another header to figure out the type of `value`.
- CarpaDorada 2y agoThe expressibility of a language is what can be expressed in it, not what it can express to you. This additional feature allows you to express this projection without being explicit.
- jeffbee 2y agoI disagree. Any language can tell the computer what to do. The quality of a good language is that it also clearly communicates to human readers.
- rileymat2 2y agoI think expressiblity is trickier than that. You can think in a language with an imperative mindset where you are describing what to do, or another with a declarative mindset.
- justinpombrio 2y agoThat's true, but unrelated to the common usage of the word "expressiveness" when talking about programming languages. There's often a tradeoff between expressiveness and the thing you're talking about, which I'll call clarity. For example, macros increase expressiveness but decrease clarity. In Racket (or other lisps), you can define a macro `(my-let x 17 (+ x 1)) -> 18`. This is expressive, as most other languages don't let you define binding constructs so easily, but also bad for clarity because `my-let` doesn't look different than a regular function, so it's hard to tell at a glance that it's doing something a function could never do.
- 2y ago
- lpribis 2y agoenum class Handle : uint32_t { Invalid = 0 }; Handle h { 42 }; // OK One of their examples demonstrates the number one issue for me with enums, which was not fixed with `enum class`. Since values outside the range of the type are valid, you are constantly needing to check for invalid values in any function that takes an enum [class]. Ruins any attempt at "parse, don't validate" style in c++ and completely ruins the "type safety" which c++ people are always going on about.
- Sharlin 2y agoWell, apparently it was fixed with `enum class`… until it was unfixed in C++17 for unfathomable reasons. It’s honestly crazy that C++ doesn’t have simple exhaustiveness-checked enums. The obvious actual solution for the valid use case of deserializing an enum from an integer would be something like template<E> std::optional<E> from_underlying(std::underlying_type<E>) requires(std::is_enum_v<E>)
- bluGill 2y agoan event loop often wants an event type enum that has defined values for internal events and then everything out of range means pass onto the users handler. There are other variations where you need to pass an enum value without caring what it mean.
- Nullabillity 2y agoThis isn't rocket science once you have sum types. enum Event<T> { System(SystemEvent), User(T), }
- account42 2y agoUsing Rusts' retarded enum keyword for your example doesn't exactly make your point understandable, especially when talking in the context of actual enumerations. Anyway, the point of what gp describes is to do this in a single integer without overhead so a naive sum type is not the solution.
- wordofx 2y agoI don’t feel like it’s an improvement. Personally prefer the explicit enum usage.
- citizen_friend 2y agoHow many meanings of the word emum do we need? Whose code does this improve?
- patrick451 2y agoenum class Handle : uint32_t { Invalid = 0 }; // process({10}); // error process(Handle{10}); > In C++14, you could use process(static_cast<Handle>(10)); so, as you can see, the C++17 version is much better. 100% disagree that the c++17 version is better. It just lets you right broken code that doesn't look broken.
- account42 2y agoAgreed, this isn't something that should be encouraged with a nicer syntax.
- WhereIsTheTruth 2y agoAll that crap is the reason I never bother with enums in all these C like languages set_player_color(player, .RED); That should be the way to use them, it's concise and typesafe set_color(Color::RED); Why repeat yourself? It's one of the things I love about Swift and Zig int main() { using enum ComputeStatus; ComputeStatus s = NotEnoughMemory; } now you have polluted the scope.. C++ have lost the plot.. they understood the issue, but they came up with a solution that's worse...
- Lvl999Noob 2y ago> now you have polluted the scope Actually they haven't. Using glob imports inside small functions can enhance readability without causing confusion. Otherwise any kind of aliasing and importing would be polluting the scope since they are bringing other items into your module without the full path.
- account42 2y agoPutting using statements inside small functions is the opposite of ehancing readbility.
- consteval 2y agoI disagree, because the scope doesn't escape those functions and it can greatly reduce the amount of :: Usually in an entire codebase or a module there's a lot of competing, similar symbols. But in a function that's not the case, because they do something small. So there's no benefit to being more "explicit", because the function already states what it does. For example you might not want to use std::chrono. But in, say, a series of timing functions you really don't want to be writing std::chrono:monotonic_clock::now(), do you? You can just use a using and then just call now() or whatever.
- jeroenhd 2y agoIt's obvious with Color, but when you deal with more complex stuff, code like computation_service.set_status(ComputeStatus::NotEnoughMemory); system.set_state(SystemState::Failure); is a lot clearer than computation_service.set_state(.NotEnoughMemory); system.set_state(.Failure); in my opinion. Both objects/structs/whatevers can have a state type of their own but the shorthand form does not indicate whether or not the two can be used interchangeably. As a workaround, you could rename the setter to set_computation_state and set_system_state but then you're just repeating yourself in a different manner that's not as precise.
- jennie258fitz 2y ago[dead]
- account42 2y agoIt's too bad that using enum is not emplicit for the cases in switch statements.
- OvbiousError 2y agoReflection is going to be a game-changer for C++. Finally!
- crowdstriker 2y agoImagine still using c++ in 2024 lmao.