Live data from Hacker News

Switching from C++ to Rust

laplab.me

171–180 of 289 posts

Re: Switching from C++ to Rust

#171

Earlier quoted context omitted.

C++ has std::variant though?

Yes, but: - nobody uses it in the ecosystem. As outlined in the article, a lot of value of Option/Result is derived from their pervasiveness in the Rust ecosystem. C++ is far from this - the ergonomics of it are terrible: no pattern matching, structural variants instead of named variants (yes you can emulate that with wrapper types but meh), lambda-oriented matching means you cannot as easily do things like early ret…

Variant types where one has to use objects as types don’t come up that often in API design or data structures in my experience with mobile and system programming on e.g. Linux. I think I’ve genuinely had to use them only a few times.

Error types are probably the most popular incarnation of that. There’s several libraries available and they will be part of the C++ standard.

This is a case of the Rust community overselling a minor feature as a game-changing novelty.

Re: Switching from C++ to Rust

#172

Rust will only be a real competitor once it’s generics can hold a candle to C++ templates.

The article specifically mentions not holding said candle as a positive. I would too. They're confusing at best and undebuggable at worst, and virtually everything you can do with them that you can't do with generics is something it'd be better for everyone if you didn't do.

Re: Switching from C++ to Rust

#173

Earlier quoted context omitted.

A union in C++ is the same thing as a struct, except all of its fields live at the same offset. So you can define any method you want on it, including special stuff like constructors and destructors. No base classes are allowed, though.

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.

At least in C, you cannot store a tag inside the union since all fields of the union live at the same offset (0) they tag will be smashed by the actual value it's trying to talk about.

In C, you have to wrap the union in a struct in order to add the tag, and that pattern is fantastically common. Let's have a little geometry-inspired example:

    typedef enum { SHAPETYPE_RECTANGLE, ... } ShapeType;
    typedef struct { ... } Rectangle;
    typedef struct { ... } Circle;
    typedef struct { ... } Triangle;
    typedef struct { ... } Polygon;

    typedef struct { // Outer struct, not a union at this level.
      ShapeType type;
      union {
        Rectangle rectangle;
        Circle    circle;
        Triangle  triangle;
        Polygon   polygon;
      }  // This can be nameless in new(ish) C, which is nice.
    } Shape;
Then you'd create a value like this, maybe:

    Shape rect = { .type = SHAPETYPE_RECTANGLE, .rectangle = { 0, 0, 20, 10 } };
Of course wrapping the initialization in a function would make it nicer.

The above union-in-a-struct wrapping is my mental model for how enums work in Rust, but I still find it jarring. :)

Re: Switching from C++ to Rust

#174
post #146

Earlier quoted context omitted.

"Panic" and "exception" is literally the same thing. Sorry you were misled, but programming is, indeed, hard, and no, you can't go shopping instead.

Panics and exceptions are not the same thing. For one, it's not possible to recover from a panic. You can handle a panic from within a handler before the program terminates, but you cannot resume execution as you can with exceptions.

You can recover from a panic though? I don't think you're required to call resume_unwind after catch_unwind. The underlying machinery is the same as C++ exceptions, so there's no reason that wouldn't work.

Obviously this is not something you're encouraged to do often, but there's applications where it might be reasonable.

Re: Switching from C++ to Rust

#175
post #72

Earlier quoted context omitted.

struct List {}; struct Cons : public List { Cons(int v, List* nxt); int v; List* nxt; }; struct Nil : public List {}; This is how you'd do it in Java.

and you would use it ... how?

I've showed you an alternative encoding, maybe get to work and learn something yourself?

Re: Switching from C++ to Rust

#176

Earlier quoted context omitted.

I know this is an unpopular opinion but if you want to stick with C++, the solution to this, at least in my experience, is to stop doing things that let you shoot your foot off. C++ gives you every tool in the tool chest, and most of them are not safe. Stick to a safe subset and you've solved 90% of all those stereotypically C++ problems. I've got a pretty big C++ codebase for my hobby projects, sanded down, polished…

> The few times I run into memory corruption, a memory leak, a segfault, dereferencing a shit pointer, undefined behavior, and so on, its always, always because I'm doing something I shouldn't be doing. Like working with raw pointers or pointers to pointers to pointers, or traversing an array of bytes to do something there's already a library that does, or manually calling delete on something, or using reinterpret_ca…

When using GCC for example, there’s a macro one can define which adds bounds checking to all containers.

Integer overflow can be turned into defined behavior through a compiler switch.

Holding pointers to stack variables past the return is not as easy to inadvertently do as an off-by-one. Someone has to store the address into a variable and this kind of code should raise alarm bells.

A more indirect way is to pass an address of a local variable to a function which is typical. But then if a function takes arbitrary pointers it receives and stores them, this should also raise some alarm bells.

Re: Switching from C++ to Rust

#177
post #138

Earlier quoted context omitted.

I know this is an unpopular opinion but if you want to stick with C++, the solution to this, at least in my experience, is to stop doing things that let you shoot your foot off. C++ gives you every tool in the tool chest, and most of them are not safe. Stick to a safe subset and you've solved 90% of all those stereotypically C++ problems. I've got a pretty big C++ codebase for my hobby projects, sanded down, polished…

Everything you said is true. C++ gives you everything you need to be safe. But that's not the point. Rust makes it HARD (or very hard) to do things that are unsafe. It's not what C++ can or cannot do, it's not what Rust can or cannot do. It's what the Rust language and compiler opinionatedly encourage you to do and not to do. This is what's lacking in C++.

I think many people - me included - are complaining that it makes things hard period. Not in the sense of “rocket science” as this argument is sometimes smugly dismissed, but in the sense of extra friction which slows things down and decreases the pleasure of coding.

Re: Switching from C++ to Rust

#178
post #25

Earlier 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…

I just wish that Rust’s enum Variants were types… maybe someday! :)

Re: Switching from C++ to Rust

#179

Earlier quoted context omitted.

This is exactly what I think too. Sum types are so powerful, I feel a lot safer in Python + mypy with sum types (`from typing import Union`) than anything with C++ [1] even though C++ has a significantly more complex type system (it's type system is TC) and Python is as type-unsafe as a language can get. C++ made this odd choice as if any complex type system is better than a simple type system. When I was a younger s…

C++ has std::variant though?

So, so many ways in which this is defective compared to actual sum types, some of them were already listed, but to me the most crucial, even if mostly about theory rather than practice, is valueless_by_exception.

The choice to provide exceptions everywhere as a error handling means C++ is obliged to admit that your std::variant may not have a value at all. Which blows up all of your type safety. In Rust I can say that this Pet is either a Dog or a Cat, and it cannot be neither, but in C++ std::variant of a Cat and a Dog might nevertheless be valueless_by_exception anyway. What can you do about that? I guess you could throw an exception...

In Rust if X is either A or B, and Y is either C or D, and Z is either E or F, then a structure with X, Y and Z has only eight possible states. In C++ this structure has 27 possible states because of exceptions.

Re: Switching from C++ to Rust

#180

Earlier quoted context omitted.

I know this is an unpopular opinion but if you want to stick with C++, the solution to this, at least in my experience, is to stop doing things that let you shoot your foot off. C++ gives you every tool in the tool chest, and most of them are not safe. Stick to a safe subset and you've solved 90% of all those stereotypically C++ problems. I've got a pretty big C++ codebase for my hobby projects, sanded down, polished…

> The few times I run into memory corruption, a memory leak, a segfault, dereferencing a shit pointer, undefined behavior, and so on, its always, always because I'm doing something I shouldn't be doing. Like working with raw pointers or pointers to pointers to pointers, or traversing an array of bytes to do something there's already a library that does, or manually calling delete on something, or using reinterpret_ca…

> You've never used an out-of-bounds index? Accidentally used an object that was on the stack beyond the function call? Let an integer overflow?

Can't speak for the OP, but I never see any of these bugs in my C++ code. You can write code with these bugs but that is more of a style choice, practically speaking. The C++ bugs I see are almost always in complex state logic or in rarer cases an unexpected/unhandled error case from a call to outside code, which can happen in every language.

Post reply on HN