The call out to sum types is something I feel. I've been using Rust daily for almost 10 years now, and sum types are absolutely still one of the things I love most about it. It's easily one of the things I miss the most in other languages that don't have them. I'm usually a proponent of "using languages as they're intended," but I missed exhaustiveness checking so much that I ported a version of it to Go[1] as a sort…
Switching from C++ to Rust
121–130 of 289 posts
Re: Switching from C++ to Rust
#122Earlier quoted context omitted.
[flagged]
Based on your other replies in this thread, as far as I can tell, you're not here to try and understand something. You're here to fuck around and play games with people over definitions. So, I'm not responding to you. I'm responding to the people following along who might get confused by the mess you're making here. More to the point, the Wikipedia article for "sum type" redirects to "tagged union," which just honest…
Re: Switching from C++ to Rust
#123Earlier quoted context omitted.
In my experience with languages that lack concise sum types and pattern matching, you end up with data types that have lots of implicit invariants. If you find yourself writing docs or thinking in your head things like "Field X is only set if field Y is true" or "If field X is non-null then field Y must be null and vice-versa", then these are indications that sum types would model the data better. Then these invarian…
i agree with your first point, but if your type-system is sufficently strong to express this, i'd like to see an example. i agree completely with your second point - passing around or storing booleans is usually horrible.
No fanciness needed, just plain old sum types. It is certainly possible to express those invariants directly in languages with a dependent type systems or refinement types like in liquid haskell - see https://ucsd-progsys.github.io/liquidhaskell-tutorial/Tutori.... It's typically much easier to reason about and use sum types, though.
Of course these examples are trivial and silly, but I see instances of these patterns all the time in big co software, and of course usually the invariants are far more complex but many could be expressed via sum types. I've seen loads of bugs from constructing data that invalidates assumptions made elsewhere that could have been prevented by sum types, as well as lots of confusion among engineers about which states some data can have.
> Field X is only set if field Y is true
Original gnarly C style pattern:
struct TurboEncabulatorConfig {
// When true, the turbo-encabulator must reticulate splines, and 'splines'
// must be non-null. When false, 'splines' must be null.
bool reticulate_splines;
struct Splines *splines;
};
Rust (let's ignore pointer vs value distinction): enum TurboEncabulatorConfig {
NonReticulatingConfig,
ReticulatingConfig { splines: Splines },
}
> If field X is non-null then field Y must be null and vice-versa.Original gnarly C style pattern:
struct TurboEncabulatorConfig {
// When non-null, lunar_waneshaft must be null.
struct Fan *pentametric_fan;
// When non-null, pentametric_fan must be null.
struct Shaft *lunar_waneshaft;
};
Rust: enum TurboEncabulatorConfig {
PentametricTurboEncabulator { pentametric_fan: Fan },
LunarTurboEncabulator { lunar_waneshaft: Shaft },
}Re: Switching from C++ to Rust
#124Earlier quoted context omitted.
Gosh I despise CMake. I despise it so much, I'm halfway through the process of extricating ESP-IDF from it.
I hate it too, but every alternative can't handle some dark corner of my build that just works in cmake.
I do this for personal projects and honestly, considering the alternatives, I think it rules.
Re: Switching from C++ to Rust
#125Earlier quoted context omitted.
To me its not just exhaustiveness but that sum types (enums) are just like product types (structs), they have have member methods, implement traits, etc. Coming from C++, when I realized Rust let me do that, it blew me away.
Actually all three of Rust's user defined types (the sum type enum, the product type struct, and union†) are fully fledged types which can implement traits and have functions of their own (including functions taking a self parameter, thus methods) C++ unions can actually have methods, although this isn't used very much. However C++ enums can't have methods, even C++ 11 scoped enums ("enum classes") can't have methods…
It is possible that Oracle holding the patent[1] to methods on enums is the blocker, rather than any technical restriction.
Re: Switching from C++ to Rust
#126Earlier quoted context omitted.
For what it's worth, the entire esp32 family is officially supported in Rust by espressif themselves [1], and the stm32 family is probably one of the most widely used cortex-m families in embedded Rust as well[2]. [1]: https://github.com/esp-rs [2]: https://github.com/stm32-rs
Right, though Espressif's official support for anything should be taken somewhat with a grain of salt ;) Having used their tools at work in anger for years at this point, there is a lot of gotchas, issues and bugs with their bindings at this point -- not all of which is Rust's fault, but the underlying problems with ESP-IDF itself. That said, its getting better over time, so I'm keeping a close eye on it (and we keep…
Re: Switching from C++ to Rust
#127Err..C++ has concepts. No duck typing required.
Re: Switching from C++ to Rust
#128Earlier quoted context omitted.
A method on a union is much less useful when you can't match on the tag though. I suppose you could store tag inside the union. Is that common? I've always imagined C/C++ tagged unions would store tag outside the union.
i haven't done c++ in a million years, but huh, you can! can't have any types w/ non-trival copy constructors in a union, though, apparently, which is quite the restriction. https://gist.github.com/erinok/c823af95db408653c7e42ab189307...
That was removed in C++11. The rule now is:
> Absent default member initializers ([class.mem]), if any non-static data member of a union has a non-trivial default constructor ([class.default.ctor]), copy constructor, move constructor ([class.copy.ctor]), copy assignment operator, move assignment operator ([class.copy.assign]), or destructor ([class.dtor]), the corresponding member function of the union must be user-provided or it will be implicitly deleted ([dcl.fct.def.delete]) for the union.
i.e., you need to provide an explicit version of the special function for the union if any member has a nontrivial implementation.
Re: Switching from C++ to Rust
#1291. how much psychological trauma it brings to average developer because today's most C/C++ library is not shipping static library by default.
2. how much pain it causes when the build system just can not copy the whole damn library into somewhere called lib and include instead spill into hundreds of random locations even we know that it will just build if we just copy it one place.
3. returning a struct with a integer status in it is so challenging for average programmers.
All these must be true because it seems it is the reality.
Re: Switching from C++ to Rust
#130Earlier quoted context omitted.
Actually all three of Rust's user defined types (the sum type enum, the product type struct, and union†) are fully fledged types which can implement traits and have functions of their own (including functions taking a self parameter, thus methods) C++ unions can actually have methods, although this isn't used very much. However C++ enums can't have methods, even C++ 11 scoped enums ("enum classes") can't have methods…
> C++ enums can't have methods, even C++ 11 scoped enums ("enum classes") can't have methods, I have no idea why that restriction seemed like a good idea It is possible that Oracle holding the patent[1] to methods on enums is the blocker, rather than any technical restriction. [1]: https://patents.google.com/patent/US7263687