Is it possible to write this Rust code into semantically equivalent C++ code?

854 views Asked by At

I stumbled upon this Rust example in Wikipedia and I am wondering if its possible to convert it to semantically equivalent C++ code?

The program defines a recursive datastructure and implements methods upon it. Recursive datastructures require a layer of indirection, which is provided by a unique pointer, constructed via the box operator. (These are analogous to the C++ library type std::unique_ptr, though with more static safety guarantees.)

fn main() {
    let list = box Node(1, box Node(2, box Node(3, box Empty)));
    println!("Sum of all values in the list: {:i}.", list.multiply_by(2).sum());
}

// `enum` defines a tagged union that may be one of several different kinds
// of values at runtime.  The type here will either contain no value, or a
// value and a pointer to another `IntList`.

enum IntList {
    Node(int, Box<IntList>),
    Empty
}

// An `impl` block allows methods to be defined on a type.

impl IntList {
    fn sum(self) -> int {
        match self {
            Node(value, next) => value + next.sum(),
            Empty => 0
        }
    }

    fn multiply_by(self, n: int) -> Box<IntList> {
        match self {
            Node(value, next) => box Node(value * n, next.multiply_by(n)),
            Empty => box Empty
        }
    }
}

Apparently in C++ version Rusts enum should be replaced with union, Rusts Box should be replaced with std::unique_ptr and Rusts Node tuple should be std::tuple type but I just cant wrap my head around how to write equivalent implementation in C++.

I know this is probably not practical (and definitely not the correct way to do things in C++) but I just wanted to see how these languages compare (C++11 features flexible enough for this kind of tinkering?). I would also like to compare compiler generated assembly for semantically equivalent implementations (if even possible).

1

There are 1 answers

1
DK. On BEST ANSWER

Disclaimer: I'm not a C++11 expert. Consume with a requisite dose of salt.

As others have commented, there's a few ways of interpreting your question. I'm going to go with an overly aggressive interpretation, since it's the only interesting one:

No, it is not possible to translate that Rust code into equivalent C++ code. Can you translate it into a program that provides the same output? They're both turing complete, so of course you can. Can you translate it so that all semantics in the original are preserved? No.

Most of it can be translated such that it preserves the actual behaviour. Rust-style enums can be replaced by structs with both a tag field and a union, along with writing appropriate operator overloads to ensure that you correctly destroy the members of only the variant that's actually stored. You can (presumably) use unique_ptr in such a way that the memory gets allocated first and then the new value is written directly into the allocation, so there's no copy. I believe you can rewrite fn sum(self) so that it uses an rvalue this (although I've never done this, so I could easily be wrong).

But the one thing you cannot do in C++, to my knowledge, is replicate linear types. There is no way to statically enforce that a moved value cannot be used again. The best you can do is runtime checks, which must necessarily involve additional overhead. This also plays into why you can't have a non-nullable unique_ptr: you wouldn't ever be able to move it, since you have to leave the moved variable in a usable state.

Now, that having been said, I should disclaim the previous statement by noting that currently, the Rust compiler emits some runtime checks for dropped (i.e. moved) values, in the form of drop flags. The plan, last I checked, was to remove these runtime checks in favour of purely static destruction, hopefully before 1.0.