Why does Rust declare function definitions in reverse?

This is similar to how functions are mathematically defined, e.g. f: R β†’ R means f is a function mapping a real to a real. See Function (mathematics) - Wikipedia for more examples.

4 Likes

To be frank, now that I look at rust after having read your post, I see a really nice design decision:
It takes many things from other languages, so much so, that it will have something in common with many programming languages, making it seem both less intimidating (Although it doesn't anyway) and offer some features that may be familiar, or easy to use after having understood them in the previous language.
For example, in rust, we use curly braces and semicolons. This applies to a huge swath of the programming language world! Next, if I recall correctly, it takes its pattern matching and superhero matching from swift. It uses type inference automatically, appealing to those languages, like js or python.

Not to mention, that thanks to its design, it might also be a breather for those who are used to having to deal with memory safety and leaks. In rust, that disappears (Mostly, unsafe still exists and is necessary from time to time).

To specifically address the question at hand, with respect to the let and let mut sequences, think about this first: When thinking about designing some code, how do you think? Do you think like this:

int a = 2
int b = 3
float dist = Math.sqrt(a * a + b * b)
return dist

or something more like this?

let a = 2
let b = 3
let dist = √(a * a + b * b)

which is closer to how I think that most people (Specifically programmers) lay out their code in the early stages, or at least in terms of an idea, they would probably think about it in terms of variables, which in this case is alot more easy to prototype.


Another point

If I should have a function like this in c:

void (*(*foo()) (std::string (*)()))(int)

can anyone (Who doesn't know c/c++) guess what this is in rust?

fn foo() -> fn(fn(String) -> ()) -> (fn() -> isize)
2 Likes

It's way older than Swift. It's mostly the same as SML97.

4 Likes

I add some languages: BASIC, Pascal, Ada, PL/SQL, Eiffel.

So much versus C :slight_smile: .

What on Earth does that function actually do?

I was thinking maybe it transformed another function which takes a string, so that that function goes from returning nothing to returning maybe a count of the characters within the string.

However, the top-level function takes a function which takes ownership of a string and whose context was defined elsewhere. So we can hardly reach in and get any useful information.

Not exactly, its completely ok for function passed as argument, to operate on global state. Example usecase (let say in pseudorust):

fn foo() -> fn(fn(String) -> ()) -> (fn() -> isize) {
  initialize_global_queue(); // Let it be blackbox
  |arg: fn(String) -> ()| -> (fn() -> isize) {
    let mut counter = 0;
    move || -> isize {
      let next_arg = get_arg_from_global_queue(); // Let it be blackbox
      arg(next_arg);
      counter += 1;
      counter
    }
  }
}

Everytime you will call finally returned function, you will call argument with some argument from magical global queue, and return how many times you already called a function. I am obviously not saying its good pattern, but in C++ I saw worse magic. Also remember, than in C++ involving global state is much much easier than in Rust (I will never say its good, but its true).

2 Likes

Holy smokes! 27 replies from 22 contributors in 24 hours? Well blogs all over the internet talk about how awesome the Rust community is, and this just proves it!

That's a wide swath of good responses that touch on a lot of good points. You all have convinced me the Rust way is actually better than the C style way. Some things that stuck out to me were:

-grepability of 'fn'
-consistency
-large function signatures that are more readable when the return gets its own space
-anonymous functions in C# read left to right which is opposite of named functions (which is silly) whereas Rust is consistently left-to-right
-specific Rust features helped by the syntax

Also, I didn't realize just how vexing C can really get (since i haven't written it in ages), until some of the examples were given. Yikes! Nice to see how Rust syntax fixes all those issues.

Thanks very much for all the incredibly enlightening responses!

17 Likes

Yes! While I wouldn't want programming to go the way of greek letters and single-character variables, the congruence we do have with the mathematical world is appreciated.

One minor request:

Can we stop with the casual ableism?

4 Likes

Add Scala to the list: def foo(): ReturnType = ...

Also C++ supports this reversed notation since C++11 and some constructs require it:

template<typename T, typename U>
auto add(T t, U u) -> decltype(t + u)
...