←back to thread

611 points LorenDB | 4 comments | | HN request time: 0.014s | source
Show context
spyrja ◴[] No.43910130[source]
To be fair, this sort of thing doesn't have to be so much worse in C++ (yes, it would have been nice if it had been built into the language itself to begin with). You just need a function to do a back-and-forth conversion which then double-check the results, ie:

  #include <exception>  
  #include <sstream>

  template <typename From, typename To>
  void convert_safely_helper_(From const& value, To& result) {
    std::stringstream sst;
    sst << value;
    sst >> result;
  }

  // Doesn't throw, just fails
  template <typename From, typename To>
  bool convert_safely(From const& value, To* result) {
    From check;
    convert_safely_helper_(value, *result);
    convert_safely_helper_(*result, check);
    if (check != value) {
      *result = To();
      return false;
    }
    return true;
  }

  // Throws on error
  template <typename To, typename From>
  To convert_safely(From const& value) {
    To result;
    if (!convert_safely(value, &result))
      throw std::logic_error("invalid conversion");
    return result;
  }

  #include <iostream>

  template <typename Buy, typename Quantity, typename Price>
  void sendOrder(const char* symbol, Buy buy, Quantity quantity, Price price) {
    std::cout << symbol << " " << convert_safely<bool>(buy) << " "
            << convert_safely<unsigned>(quantity) << " " << convert_safely<double>(price)
            << std::endl;
  }

  #define DISPLAY(expression)         \
    std::cout << #expression << ": "; \
    expression

  template <typename Function>
  void test(Function attempt) {
    try {
      attempt();
    } catch (const std::exception& error) {
      std::cout << "[Error: " << error.what() << "]" << std::endl;
    }
  }

  int main(void) {
    test([&] { DISPLAY(sendOrder("GOOG", true, 100, 1000.0)); });
    test([&] { DISPLAY(sendOrder("GOOG", true, 100.0, 1000)); });
    test([&] { DISPLAY(sendOrder("GOOG", true, -100, 1000)); });
    test([&] { DISPLAY(sendOrder("GOOG", true, 100.5, 1000)); });
    test([&] { DISPLAY(sendOrder("GOOG", 2, 100, 1000)); });
  }

Output:

  sendOrder("GOOG", true, 100, 1000.0): GOOG 1 100 1000
  sendOrder("GOOG", true, 100.0, 1000): GOOG 1 100 1000
  sendOrder("GOOG", true, -100, 1000): GOOG 1 [Error: invalid conversion]
  sendOrder("GOOG", true, 100.5, 1000): GOOG 1 [Error: invalid conversion]
  sendOrder("GOOG", 2, 100, 1000): GOOG [Error: invalid conversion]

Rust of course leaves "less footguns laying around", but I still prefer to use C++ if I have my druthers.
replies(1): >>43912644 #
pjmlp ◴[] No.43912644[source]
Yes, from safety point of view Rust is much better option, however from the ecosystems I care about (language runtimes and GPU coding), both professionally and as hobby, C++ is the systems language to go, using Rust in such contexts would require me to introduce extra layers and do yak shaving instead of the actual problem that I want to code for.
replies(1): >>43921048 #
spyrja ◴[] No.43921048[source]
Well, precisely. Such is the price of "general-purpose safety". The biggest irony IMO is that the security features of Rust are so often skirted in the name of speed, efficiency, etc, with the end result being a program which isn't much more secure than its C++ equivalent. ¯\_(ツ)_/¯
replies(2): >>43921386 #>>43923359 #
1. steveklabnik ◴[] No.43921386{3}[source]
> The biggest irony IMO is that the security features of Rust are so often skirted in the name of speed, efficiency, etc, with the end result being a program which isn't much more secure than its C++ equivalent.

Citation needed. The empiric evidence I’ve seen has shown the opposite.

replies(1): >>43921786 #
2. spyrja ◴[] No.43921786[source]
Overall it does indeed seem to be the case for roughly 25% of Rust crates:

https://rustfoundation.org/media/unsafe-rust-in-the-wild-not...

https://thenewstack.io/unsafe-rust-in-the-wild/

https://github.com/sslab-gatech/Rudra/blob/master/rudra-sosp...

https://internals.rust-lang.org/t/canvas-unsafe-code-in-the-...

Again, not a criticism of the language itself per se, and certainly not trying to imply that all Rust programmers go around writing unsafe code all day long. It's just kind of funny to me that it is touted as being so much more safe than C++ when the reality is that at least some of those features are in fact disabled for one reason or another in real-world programs.

replies(1): >>43921943 #
3. steveklabnik ◴[] No.43921943[source]
> Most of these Unsafe Rust uses are calls into existing third-party non-Rust language code or libraries

This is very different than

> in the name of speed, efficiency, etc

And also does not demonstrate that

> the end result being a program which isn't much more secure than its C++ equivalent.

At all.

replies(1): >>43922233 #
4. spyrja ◴[] No.43922233{3}[source]
What are you trying to say? C++ can be just as safe as Rust. The latter is just easier to use, especially in terms of working as a team of developers insomuch as the safety-nets are by default in place. Once again, C++ is powerful but comes with just as many footguns as C (in fact, more) and so requires a bit more finesse, experience, and skill to work with safely. Otherwise it can encapsulate pretty much any functionality you could possibly imagine, and that includes safety features. Checked memory accesses, managed memory, well-behaved arithmetic, all of that and more can be codified as a set of objects and interfaces. I started out in assembler, worked up to C, then finally on to C++ where I actually found it quite easy to write safe programs by just sticking to a strict set of guidelines. And that works. I have code that has been running almost continuously for over a decade without a hitch, and I credit that to good programming practices.