Rust, Ruby, and the Art of Implicit Returns
earthly.dev
earthly.dev
I am surprised and delighted to learn that in fact, many modern languages have been doing this. Particularly seeing this in Rust raised my eyebrows, given how system-focused it is. I'm curious from the Rustaceans out there: Is it common to use the conversational nature of expressions and implicit returns? Or does it frequently create unwelcome dissonance?
Whenever I switch to Python, JS, C#, the explicit returns catch me for a day or two. I always think "We're already reserving this value in memory to evaluate that last line, why don't you let me do something with it if I want?". But I know folks who swing the other direction and feel quite the opposite -- things feel out of place and not-obvious.
Either way, thanks for the well-written article. It has added influence to my "I think I want to look at Rust -- it feels familiar."
> Is it common to use the conversational nature of expressions and implicit returns?
I have found that most people who do not have experience in expression-oriented languages end up confusing themselves because of it. They'll ask how you're supposed to know where a function returns, when a return can just happen anywhere. But it can't! That's not how it works!
Like any new concept, it can take some time to wrap your head around how it influences how you write code. But I think that the end result is far better. Compare this lambda in C++:
[](int n, int x) { return n < x; }
to this closure in Rust: |n| { n < x }
there are multiple reasons why the Rust is shorter here, and you can argue some of them are better or worse, but not needing the return and semicolon here makes it easier to read, at least for me.But I think that sometimes people who learn about "implicit returns" write things like iterator chains, that take closures, not even realizing that they're using "implicit returns" in that circumstance. It just feels natural, especially in simple cases like this.
But also, I've been mainly writing in expression-oriented languages for the majority of my professional career, so of course it makes sense to me.
In GNU C, if a braced compound statement is put into parentheses, it becomes an expression. The value of the last expression in the compound is implicitly returned:
// c receives 5
int c = ({ int a = 2, b = 3; a + b; })
Never mind that; the standard C macro preprocessor has "implicit return": // not return #define max(x, y) return ((x) > ...
#define max(x, y) ((x) > (y) ? (x) : (y))
Note that the "implicit return" in Lisp is just from mathematics: f(x, y) = x^2 - y^2
Not: f(x, y) { return x^2 - y^2 }
the return keyword is kind of a disease/blemish, introduced by way of Blub programming languages."Implicit return" is like saying "face with implicit warts" in reference to a face that is perfectly smooth and never had a blemish.
In functional languages, there is only one expression which makes up the body of a function and of course that expression's value is yielded; it's the definition of the function.
Explicit return is a form of goto; it's required only in imperative programming, and even there we can leave it out for the last statement.
The C preprocessor doesn't have a return operator because it's a functional, term rewriting language. Every definition has one replacement in which there are no side effects or goto.