C++ vs. Rust: Factorial

Let’s dig a little bit in some implementations (in C++ and Rust) of a function that computes the factorial of an integer passed as argument. I will try to make them as similar as possible and will expose the differences between both:

Recursive factorial

This is the simplest and most known factorial implementation:

int factorial(int n)
{
    if (n <= 1)
        return 1;

    return n * factorial(n - 1);
}

Now, the “same” implementation in Rust:

fn factorial(n : i32) -> i32
{
    if n <= 1
    {
        return n;
    }
        
    return n * factorial(n - 1);
}

Though similar and probably producing the same binaries, there are very interesting differences to take into account:

  1. All functions in Rust start with the “fn” keyword. In C++ they start with the function return type, void, or auto.
  2. In Rust you must specify the return type after ->. Since C++11 you can do the same if you mark your method as “auto“. If you do not specify the return type, the function does not return anything (like a C++ void function).
  3. The Rust type “i32” refers to a 32-bit integer. In C++ “int” represents an integer that could have (as far as I know, all current implementations have a 32-bit integer called: “int“) a 32-bit representation. This could be not true for old platforms, compilers or very small ones where the int could be 16-bit. Having an integer with well-defined size for all platforms make code portability easier. (C++ also have the int32_t alias, but is not an actual type).
  4. Rust’s “if” discourages the usage of parenthesis in the expression to evaluate.
  5. Rust mandates the “if” and “else” blocks will be enclosed with curly braces.

Non-recursive implementation

C++ version, using “while“. I am not using “for” because the C/C++/Java/C# -like “for” does not exist in Rust.

int nonRecursiveFactorial(int n)
{
    int r = 1;
    
    while (n >= 1)
    {
        r *= n;
        n--;
    }

    return r;
}

And now, the same code in Rust:

fn non_recursive_factorial(mut n : i32) -> i32
{
    let mut r = 1;
    
    while n >= 1
    {
        r *= n;
        n -= 1;
    }
    
    return r;
}

Again, interesting differences:

  1. I called “nonRecursiveFactorial” my function in C++ and “non_recursive_factorial” my function in Rust. Though I can call my functions whatever I want, the Rust compiler suggests me to use snake_case instead of camelCase.
  2. Notice I marked my argument as “mut” and my variable rmut” as well. “mut” stands for “mutable” and means that the value of that variable can be modified in its lifetime. All variables in Rust are immutable by default (similar to a C++ const variable) and that simple feature removes a lot of concurrency problems.
  3. Again, while does not have parenthesis in its expresion.
  4. Notice I am writing n -= 1; instead of n--; in Rust. Rust does not have “++” or “--” operators because their existence would make lifetime management complicated and the code with those operators can be hard to read in some scenarios.

I want to use “for” anyway

C++ version:

int factorialWithFor(int n)
{
    int r = 1;
    
    for (int i = 2; i < n + 1; i++)
        r *= i;

    return r;
}

Rust version:

fn factorial_with_for(n : i32) -> i32
{
    let mut r = 1;
    
    for i in 2..n + 1
    {
        r *= i;
    }
    
    return r;
}

Once more, interesting differences:

  1. The “for” loop in Rust is a range-based-for-loop, similar to the C++11 range-based-for-loop or C# foreach.
  2. The variable i inside the loop is mutable, it is declared and lives only in that block.
  3. After the “in” Rust keyword, I wrote “2..n+1“. That is the Rust way of creating a range of values between [2; n + 1[ (so the loop will run until n only).
  4. If I would want to have a countdown instead, I could write “(2..n + 1).rev()” instead, that would downcount from n to 2.

Until now, very nice language indeed.

Advertisement

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s