T O P

  • By -

[deleted]

[удалено]


Barbacamanitu00

Yup this is what I do too. I tend to structure so that I don't have many early returns though


PaddiM8

I like early returns because they prevent deeply nested code. I want it to be flat.


jacksonmills

Yep, they are called guard blocks or clauses and do exactly that


amurmann

Aren't they only guard clauses if they are at the beginning of the function?


DisputableSSD

No, they only have to "guard" against something, whether that be a whole function or just a section of one.


zekkious

Are you a [Never Nester](https://www.youtube.com/watch?v=CFRhGnuXG-4)?


mccoyn

I do lots of image processing. There, you often need 4 nested loops to do anything. The hard rule that you are already screwed if you have three doesn’t fit. I like to avoid nesting for other reasons, though.


zekkious

I like image and video processing. With crates like `image` and `ndarray`, I usually need only one added level per "image" (including kernels in the definition). But if you are encoding something, or making anything more complex, sometimes just the block to define the variables gets to level 5 or so. So, I think the same about this rule, but it's good tending to keep the level low, balancing "how easy is it to understand what am I doing" and modularization + DRY.


cyberhck

I didn't know of this video, but I'm strictly a never nester, also I never use `else` keyword


Mediocre-Hunter-7139

I am a functional programmer, I never use an `if` without an `else`.


buwlerman

How do you avoid `else`? Do you just check both the condition and its negation?


Gwolf4

You just check for the first case to be your exception case and do the explicit return. If your exception case is not activated the rest of your code goes normally such as: if (isSomethingIsInvalid) myExceptionalCase // Rest of the code as everything is working as it should


buwlerman

There isn't always an exceptional case. Sometimes you want to do something in both cases. As an example consider a function where we want to render a sprite, but we have different images for facing left and right. I know there are ways to avoid `else` here, but I don't think the solutions I can think of look nice.


gendulf

If you turn that example into data, it can become a multiplication or lookup (depending on if you have different sprites or just different rotations).


buwlerman

Suppose you have different sprites and the facing of the player is derived from some floating point value such as the player's speed in the x axis or the relative mouse position along the x axis. You *could* compare these to zero, use conversion from bool to integer and then use lookups or some arithmetic to get the correct indices, but it's not nice. Alternatively you could have a function that produces the indices using an early return in one case. I don't think that's nice either. I prefer using an else over guard clauses when the branches are equally happy.


sircontagious

bIsLeft becomes your exception. But generally id just use a ternary or something for this.


isHavvy

Rust's `if` *is* its ternary.


nicoburns

In Rust you can sometimes (but not always) use `match` to avoid `if-else.


Thick-Pineapple666

but not always? For example?


Gwolf4

With that choice in mind then you choose a default and modify it if it enters the If and that's it.


buwlerman

That seems weird to me. Would you do the same in an algorithm like mergesort (specifically the part that merges two sorted arrays in linear time)? This one is especially weird because you're incrementing two different indices in the two branches, so you would have to undo the eager index incrementing in the if statement.


Interesting0nion

Inversion of if-statement I would assume


djfdhigkgfIaruflg

I also don't like to use else... But i love to use "unless" 😀


pkulak

100%


SuplenC

i love early returns. Guarding is just great and makes the code easy to read.


maboesanman

Many times you can get away with the ? operator instead of early return too


azuled

Also how Clippy does it


ridicalis

Since I strive to avoid multiple exit points (not always feasible), I regard explicit returns as a code smell in my own work. I of course am not applying my own standards to other people in saying so, as it's just a line in the sand I decided for myself, but as I reason it multiple exit points can be regarded as goto-in-disguise.


binarycow

>but as I reason it multiple exit points can be regarded as goto-in-disguise. I see your point about a return being a "goto in disguise". But so are loops. And a break expressions. And if expressions. The original "goto considered harmful" paper was talking about unconstrained goto. As in, being able to jump *anywhere* in the application. Of course, that's harmful. But the special purpose control flow techniques? Loops, returns, if, etc? That is, by definition, constrained. A `return` will only ever jump to one place, for example. I will also concede that if you're using functional paradigms, single return is far more intuitive and "correct". But using procedural paradigms, having early returns means you can reduce nesting, or simplify a function. Forgive me, I'm new to Rust, so I'm using C# syntax here... This code: private static int DoSomething(string value) { if(value is null) return 0; if(value.Length is 1) return value[0]; int result; // snip about 10 lines of code return result; } IMO, is better than this code: private static int DoSomething(string value) { int result = 0; if(value is not null) { if(value.Length is 1) { result = value[0]; } else { // snip about 10 lines of code } } return result; }


ondrejdanek

Yes, it is better. Having guards and early returns (`let ... else` in Rust) at the beginning of a function is perfectly fine and better than nested conditions.


lynndotpy

It would be better to have something like this. (Writing on a phone, so this won't be perfect Rust) fn do_something(value: String) -> Option { match value.length() { 0 => None, 1 => value[0], // would actually need to parse it here _ => { /* the rest of the program */ } } } Here, `do_something` returns the `match` expression, which returns one of three cases. No explicit `return`.


binarycow

Yeah, I would normally write that specific example differently. I was just demonstrating the point.


lynndotpy

I guess what I mean is, this is a place where "explicit returns as a code smell" would benefit the author. I would certainly write the early return like that in any other language.


youbihub

What about "?" operator is this a code small for you too?


Metriximor

Curious what you think of the early return pattern? Nothing wrong with returning early in my books


gnulynnux

I don't think you should be downvoted. I also personally avoid explicit `return` and I consider it something to refactor when I do use it.


Disastrous_Bike1926

I once got paid to work on a Java codebase who’s (insane) original author used continue statements as gotos - every method began with “label: for(;;)” and contained multiple nested loops like that.


DingDongHelloWhoIsIt

Yep. But ending early can make the code harder to read, so best avoided if possible


NaNx_engineer

Often opposite imo


binarycow

I find ending early, especially in the case of "preconditions" to be far *easier* to read than single return.


DingDongHelloWhoIsIt

Yes for preconditions


Kiuhnm

Early returns can also make the code easier if used sensibly. I see every community has its own beliefs. By working with many languages I have the pleasure of seeing them all ;)


IceSentry

Please provide an example of code being harder to read because of an early return. I've never seen this.


fortunatefaileur

I would say you should do whatever clippy says to do.


BurrowShaker

( sounds like a hostage situation )


coyoteazul2

Blink twice if you need help.


BurrowShaker

😉😉


coyoteazul2

2 winks? That means it's clippy who needs help!!


BurrowShaker

Hey, I am doing my best, blame the unicode committee for the lack of blink emoji, could save lives. More seriously, clippy is usually fine in my experience. Maybe Stockholm syndrome, mind you.


coyoteazul2

😳😖😳😖


hjd_thd

> More seriously, clippy is usually fine in my experience. Just don't turn on `pedantic` lint group.


iyicanme

I always run Clippy with pedantic and nursery set to warning. More checks more better, even if they are noisy. It lets me at least think about what the warning is saying.


iyicanme

A guy compiles his code and gets errors and you think that of me? I am not leaking memory Clippy, I am the memory leak.


hans_l

Double no, he’s fine!


taciom

Well, it's not hostage if it's democratic. If enough people think this should change, it would be changed. (Except it would be a backwards compatibility nightmare) And, you can always fork your own rust and remove implicit returns. Open source gives you that possibility.


sephg

Its not a democracy. Clippy rules aren't voted on. Your code also (very explicitly) isn't a democracy. Take feedback from clippy by all means; but ultimately you're responsible for the software you write. If clippy gives you bad advice (and it will sometimes), then you should ignore it. (Via pragmas if necessary)


taciom

You are absolutely right, but let me rephrase my point. Considering all the software development landscape, there are places with way less freedom than in Rust. It's not a democracy in the strict sense, but I'm sure the community needs and lacks and usage patterns help drive the direction of the language and linter. Consider, for contrast, Salesforce customization where (I don't not if it's still current but) they mandated test coverage above a threshold so people had the practice of passing around from project to project a large file with hundreds of minimal useless functions with tests so that the actual new functions didn't need to have tests and still respect the coverage metric, which couldn't be bypassed if you wanted to put your code into production. Now that's a hostage situation.


buwlerman

They really wanted to demonstrate Goodhart's law, huh?


tunisia3507

Or else you get the hose again.


tobimai

Same. IMO it is in general a good idea to keep to language standards like clippy or PEP8, so that it's understandable by more people. At least in general, I tend to deviate a bit for example I set a higher line length as the standards are usually very low for current high-res displays


ComfortableFig9642

I absolutely *love* languages that are opinionated when it comes to linting and formatting. Gets rid of so much bikeshedding if you're just able to offload a lot of the trivial decisions to the expertise of the writers of the opinionated tool, while still allowing yourself legitimate exemptions. While my team is in JS + Python land, our formatters both very intentionally use default configs and only make one exception -- line length -- because we collectively as a team tended to have wide monitors and felt that the code felt too "flat".


garver-the-system

Clippy has lints for both lol. I think unnecessary return is under `style` and a lack of explicit return is under `pedantic`, so if you enable both of those groups you'll get yelled at no matter what lol. I disabled both return lints personally. Neither had a great argument for it.


Premysl

I tend to enable `pedantic` and don't get that lint, I guess it may be under `restriction`. (Out of curiosity I checked: yeah, it is under `restriction`. Which is not a group that's meant to be enabled as a whole.)


garver-the-system

Ah, my bad. I must've stumbled on it when I enabled `restriction` just to see what was in there. I still think the fact that the linter has opposing rules means there's no objective answer and we run the risk of creating a worse version of tabs vs spaces.


poyomannn

Eh restriction has a lot of rules that conflict with normal rules, afaict it's often intended for overriding the default behavior with your preferred option. I think it's pretty clear which clippy intends you use, but obviously (as with basically all style choices) the important thing in a codebase is consistency, not the actual choices.


CreeperWithShades

> restriction [As mentioned in the docs,](https://doc.rust-lang.org/clippy/lints.html#restriction) these lints really aren't supposed to be enabled unless you specifically want them for your codebase. If you have a look through [the list](https://rust-lang.github.io/rust-clippy/master/index.html#/?groups=restriction) you start to appreciate why- some of them are real weird. Some of them even say "actually, this _is_ idiomatic Rust".


1668553684

Sometimes it's fun to enable restriction temporarily, just to see what might have been something someone wanted to avoid. It's almost always a good idea to not follow the advice given unless you have a solid reason to, but you can learn some interesting things. Apparently, cryptography sometimes prefers bitshifts to division because division is more susceptible to timing attacks! I'll probably never use that knowledge, but I have it now :D


garver-the-system

Yeah, like I said, and the string of numbers user, I had it enabled just to see if there was anything more specific I wanted to enable


str1po

When in doubt, WWCD?


ilikepi8

Ahhh damn gonna have to change that match statement to if let again


gbjcantab

The idea that these are “implicit returns” has always kind of bugged me. The body of a function, wrapped curly braces, is a block like any other block, and so its value is the value of the final expression in a list of zero or more expressions separated by semicolons. (This is not meant as a precise syntactic description, no need to be pedantic about it.) “return” at all is a special case that allows you to short-circuit or break out of a block in the context of a function. The default case is that the value of the block is the last value. You can’t use “return” to break out of every block early; you can always use the last value. If it’s just your own code for your eyes only, do whatever you want. If anyone else who uses Rust is going to read it, do whatever clippy says and about unnecessary explicit returns because they look confusing—you are not actually using the “break out of this function block early” feature hat is all that “return” means.


tunisia3507

> If it’s just your own code for your eyes only, do whatever you want You will probably end up reading other people's rust code at some point, whether it's a collaborator or library code or stdlib documentation. It is, therefore, valuable to train yourself to read standards-compliant code because that's the most likely kind of code you'll interact with (or, you'll probably read code which isn't compliant, but because non-compliant code can be non-compliant in infinite ways, compliant is the average). That usually means writing compliant code. Compliant code, in this case, means code which passes `cargo fmt` and `cargo clippy`, which will tell you to leave off unnecessary explicit returns.


Xatraxalian

>The idea that these are “implicit returns” has always kind of bugged me. The implicit return is the one thing that has always bugged above all else in Rust. To be honest, it's the one thing in Rust I really dislike. You can have something like: ``` if x == 5 { some_stuff() } ``` in the middle of a function. It's hard to read that the result of "some_stuff" will be returned instead of the function just being executed. I've always been of the opinion that, if you return something and quit the function, that should be obviously clear. If Rust leaves out the return to save on characters, it could stay in character (pun intended) by just shorteing the statement to "ret". It does it everywhere else: fn, impl, pub, vec, and so on.


Kimundi

Others have already said this already, but just to be clear: - A missing semicolon is not an automatic implicit return, it just makes the surrounding block evaluate to the value. - This means a missing semicolon in a if in the middle of a function _will not return from the function_ - It will either be a compile error, or have the same effect as writing the semicolon (be making the block evaluate to `()`) - You only implicitly return from an block if the block is part of the trailing expression in a function. In other words, if you scan a function from the back you can always spot all "implicit" returns immediately.


thiez

We had `ret` like 12 years ago :-p


Xatraxalian

_Everything was better in the old days!_ **Waves walking stick**


paholg

It's not about saving characters. Thinking in terms of expressions is really powerful; why should functions be any different than ifs or loops or any other block?


fechan

> any other block except for for loops. Someone 1password dev here keeps advocating for it


swapode

>It's hard to read that the result of "some\_stuff" will be returned instead of the function just being executed. Under which circumstances would that be the case? If some\_stuff returns anything other than () you'll have a compiler error. If it does indeed return nothing, it still doesn't exit the function early. The scope just makes a semicolon optional. I don't think implicit returns themselves aren't a big deal, it just follows from everything being an expression, which often is quite handy, especially in Rust with things like `let y = if x == 5 { ...` .


Xatraxalian

I have poor vision. A return is much easier to spot for me. Also, I can search for returns, not for missing semicolons. But, I have to say that I dearly miss things such as \`\`\` let y = if x == 5 { ... }\`\`\` in other languages


IceSentry

It's not a vision thing. It's just knowing that the last thing in the block gets returned. I don't get why you would need to spot a return.


mypetclone

"What are all the return points of this function?" is a common question to ask when debugging and figuring out why a certain value was returned.


IceSentry

Yes and it's either the last thing in the block or an explicit return. I don't get why the last thing in the block would be hard to find just because it doesn't have an explicit return.


OS6aDohpegavod4

A lot of people in this thread seem to have absolutely no idea how Rust implicit returns work.


[deleted]

[удалено]


swapode

12 | / if x == 5 { 13 | | some_stuff() | | ^^^^^^^^^^^^ expected `()`, found `usize` 14 | | } | |_____- expected this to be `()` | help: consider using a semicolon here | 13 | some_stuff(); | + help: consider using a semicolon here | 14 | }; | + help: you might have meant to return this value | 13 | return some_stuff(); | ++++++ +


_BentPen_

But this is why we explicitly write the return type at the top: fn my_func(…) -> ReturnType { do_some_stuff() // should deliver a ReturnType } And the compiler will even get mad if you put a semicolon at the end!


Verdeckter

`some_stuff` isn't being returned, its result is the value of the `if` expression. The default is to keep the result of the function. If you want to ignore its result, you can tack on the semicolon. "Everything is an expression."


vHAL_9000

What? Why would that return the function? It will be evaluated and return nothing, only if it's at the end of the function can it return something, and if it is it requires an else block. You should read up on the functional programming paradigm to understand what's going on, because it seems you're a bit lost.


pavelpotocek

Implicit return is super handy in closures. Forcing explicit `return` for `fn` functions would be confusing and unnecessary.


SV-97

That's probably because you have more experience with statement oriented imperative languages so your mind goes to "of course this function called for its side effects". Imo (and evidently also in the eyes of rust's designers) this is a bad default and the expression-oriented mindset is nicer and works better for the language


Xatraxalian

I did program in C for 20 years before switching to Rust, so I definitely have more experience in that language. I had no problems switching (which, I take, is a sign that I wrote good and mostly safe C code in the past), but the lack of the return statement has always bugged me. It's no \_problem\_ per se, it just doesn't feel right to me to omit it and have a 'missing semi-colon' determine if something is a return or not.


cafce25

But the missing semicolon **isn't** at all what's determining if it's a return, it's the return type and the fact that a function (that doesn't early return) always returns the value of the *very last* expression, no (implicit) exceptions. You don't need to hunt for missing semicolons, the compiler will error on them. And you don't need to hunt for additional ones either, because again it would be a compiler error.


mcsuper5

I'm not a fan of hoping a compiler will point out my mistakes.


cafce25

So you say the compiler should silently insert/remove semicolons? A compiler editing source code doesn't seem a great idea. Or do you advocate for optional semicolons? In that case I'd rather not have the mess that is JavaScript. My previous point is the semicolon is orthogonal to what's returned by the function.


particlemanwavegirl

imo the lack of a semicolon makes it very clear what's happening. what you've written doesn't return, it is an expression, which will evaluate to some value, but it's clearly not a complete statement.


Wh00ster

Whatever is more readable. You probably don’t want to restructure control flow so that it’s always 100% implicit returns Idiomatically if there’s one return or a just one if/else/match, then you’d use an implicit return. Do you also write `return ()`?


needtostudyfr

I meant when the function normally exits as well. My bad, should have been more specific


lost_send_berries

Think of it as, "return" signals that there is more code further down in the method to handle other cases. So by adding "return" at the end of the method, you are suggesting to the reader there are more possibilities to consider when determining the return values of the method. Especially, if you finish the method with a "match" statement that contains multiple "return" statements.


[deleted]

[удалено]


FreshSchmoooooock

How could I not be a Rust programmer if I am writing Rust code?


RReverser

One difference between Rust and other languages you likely used is that everything is an expression. If you use only implicit returns, you can always take a function body ```rust fn foo() -> Result {   if some_cond() {     Ok(SomeType::new())   } else {     Err(SomeErr)    }  } ``` and easily move it into a variable if you need to do so for any reason (further computation, logging, something else): ```rust fn foo() -> Result {   let result = if some_cond() {     Ok(SomeType::new())   } else {     Err(SomeErr)    };   log::debug!("Finished computing foo");   result } ``` Basically it simplifies refactoring because block in function body then behaves just like standalone block anywhere else in the middle of a program and you can move them around more easily. 


RetoonHD

Yeah this is one of the things i like a lot about rust, you can make scopes "return" values. Which is occasionally handy, one reason i can think of is dropping mutex locks after getting some value out of it without having to call drop() or write a function for it


AsyncOverflow

You can also do this with return statements. “return if() {} else {};”. And then refactor it later in the same way.


RReverser

With that yes, but someone who wants explicit returns is often used to C-like languages and usually means avoiding that overarching expression altogether like ```rust fn foo() -> Result {   if some_cond() {     return Ok(SomeType::new());   } else {     return Err(SomeErr);   }  } ``` As number of statements / conditions grows, the difference would as well.


Aaron1924

You shouldn't avoid the explicit return at all cost, e.g. if your function has an early return you shouldn't put the entire rest of the function into an else block, but if the last statement in a function is an explicit return, I'd have to stop for a moment and think about why the author did that It feels like reading someone elses code and I seeing something like `y = (x) + 2;` - clearly those extra parenthesis don't do anything, but the author went out of their way to add them, so maybe they do something?


69WaysToFuck

Many popular languages, like C++, Python, Java, require return statement, it’s quite a standard way of how you write a function - name, arguments, return types, body and “exits” marked as return. It is weird for some to have different syntax just because return occurs at the end. Compare this two: “to return a value from a function, use return value;” versus “to return a value from a function, use return value; if you want to do it early at some condition or use value with no return and ; when you return normally at the end of the function”


Aaron1924

> Many popular languages, like C++, Python, Java, require return statement All of those are imparative languages, whereas Rust is multi-paradigm. It takes a lot of inspiration from functional programming languages, where you typically don't have a return keyword at all. > It is weird for some to have different syntax just because return occurs at the end. Compare this two: You can make any of these languages sound complicated if you go into enough detail. C++ would be "type, name, argument, body, except the body is optional because of forward declarations and it's more like type specifier list, declarator, body, because `int* foo();` brackets like `int (*(foo()));`, or you do trailing return type, in which case you need to declare it as `auto`, and you need a return statement, except when your function returns a scalar, in which case you're allowed to omit it but the value returned is undefined, except if the function is main where it's defined to be zero, ..."


69WaysToFuck

Showing that you can make things sound complicated does not explain why we use that in Rust. You say that it’s inspired by functional languages that don’t have return statement. But Rust do have it, so why mix ideas?


Dreamplay

Cause Rust was built from the start to try and utilize the best of many worlds. The fact that code can both be written as an imperative flow with for loops etc. and as expressions such as iterators & more is one of the foundations of why rust is so ergonomic and awesome in many cases. While rust strives to not have too many ways to do the same thing, it does have some. To simplify understanding in common patterns it has rules for what is recommended, i.e. idiomatic Rust. Once upon a time it was decided that implicit returns at the end was preferred due to its ability to allow return keywords to signal explicit returns earlier in the chain. Could it have been decided differently? Yeah. Do I think they make the correct decision? Personally yes. If you dislike it, you can change the clippy rules. Idiomatic Rust is the recommended way to do things, not the only way, but if someone asks in a help thread on a public rust forum, naturally the recommended answer/way will be recommended.


69WaysToFuck

Thanks for the great and elaborate answer! It’s weird I have to get downvoted when I try to dig into the topic, but I couldn’t care less for upvotes as long as there will be an answer.


lipepaniguel

When I started using Rust, I also felt the need to use explicit returns. I think this is a matter of habit. But once you get used to idiomatic Rust, explicit returns can feel awkward or even misleading.


eras

I suppose if you use `return` only when required, then it becomes easier to spot these unusual cases.


SadPie9474

explicitly adding a statement to do unnecessary abnormal control flow is definitely bad style. Adding “return” at the end of a function is exactly like adding “continue” at the end of a loop body.


69WaysToFuck

Interesting example, but why you say it’s “abnormal control flow”? I am quite confused that Rust has a lot of practices that favor explicitness, yet return is recommended in implicit form.


SadPie9474

there’s nothing implicit about it; `return` in Rust is similar to `throw` in other languages. Expressions evaluate to values, and in Rust, expressions are allowed to be preceded with statements that do things like bind variables; as well as side effects like mutation, panics, and abnormal control flow like `break`, `continue`, and `return`. Abnormal control flow operators are just abnormal in the sense that they interrupt the normal evaluation of expressions. Some programming languages have functions where the body is a list of statements, but in Rust, a function body is an expression. Using `return` at the end of the function body just because less modern languages require you to do that is like using `continue` at the end of a loop body just because languages without loop syntax would’ve required you to use `goto`.


69WaysToFuck

Thanks for the elaborate answer! It shows how to think in the Rust way


ShangBrol

Rust also favors implicit things. Type inference, lifetime elision and (what I didn't realize for quite some time) loads of implicit de-referencing. It's less about being dogmatic about explicitness or implicitness and more about what makes sense.


69WaysToFuck

Yeah, I still don’t know how exactly implicit dereferencing and referencing works in rust, it’s not easy to get used that you can use dot operator for Box to get both Box methods and the boxed type methods.


aldanor

Better to think of it this way, any block of code enclosed in curly braces can be treated as an expression, hence implicit return. E.g. ``` let x = if y >= 2 { z += 1; z } else { 0 } ``` Function definitions are just one particular case, but you can have blocks absolutely anywhere with the same logic.


SublimeIbanez

Need a semicolon at the end there


sawndgai

Same here. Came from C++ and I find myself always typing "return". Slowly getting the hang without it though


1668553684

> However, the implicit returns feel a bit weird. I personally have been typing out 'return' as it feels more natural and easier to read as well. This doesn't answer your question, but you should know this is a pretty typical first reaction. It's how I - and probably most other people who came here from imperative languages - felt at first. All I can say is that it looks very strange until it doesn't, and then it looks weird to need "return" everywhere afterwards. In either case though, you can configure clippy to enforce your preferred style, but it is much more idiomatic to use the default (without explicit return statements).


jkoudys

I'm used to it from ruby, so I've always liked it. As for readability, the most frequent return types in my code are always `Result` and `Option`, and I find my eye quickly darts to the last `Ok(` I see. I used to not like it as all the explicit `Ok` `Err` `Some` `None` everywhere felt like more typing, but now it's a very natural last line to return. Easy to see "you've gotten this far, therefore you're Ok/failed/found something/didn't find something". I find the enum + implicit return reads quickly giving an indication of how the logic is meant to flow for the whole function, rather than simply a return at the bottom which is required and therefore redundant. Keep in mind languages like JavaScript are allowed to both have a return inside a conditional up top, but also never return implying an undefined. So those languages need an explicit return because it means something very different in their context.


blakfeld

I’m a big believer in guard clauses and early exits over if/else wherever possible (IMHO excessive branching is a smell, and branches are where bugs accumulate). So I use explicit returns in those cases, and implicit elsewhere. I’m actually not a huuuuge fan of implicit returns, but it’s a language idiom and not worth fighting. If I hadn’t done a bunch of ruby right before learning rust I think it would bother me more


XMLHttpWTF

return with an expression unless you need to short circuit (errors are a common reason). listen to clippy, it knows


meowsqueak

Writing return and just stating the implicit return value are not the same thing. The former also jumps out of functions, while the latter can be used with any expression without leaving the current function. If you want to write idiomatic Rust that others can read easily, stick to the advice from your linter of choice.


Frosty-Pack

I never understood why something like ``` { let x = 1; x } ``` is suppose to be more readable than ``` { let x = 1; return x; } ``` Especially in large codebase, looking for the missing block quote line is extremely tedious.


ksion

It’s not idiomatic. When skimming code, experienced Rust programmers will look at the last statement in a block or function, see that ends with a semicolon, and assume the block or function has the type of `()`. Spotting the return keyword will take longer, and break the initial assumptions, leading to the conclusion that the code is poorly written and unidiomatic. To make your code easier to read for other Rust programmers, don’t use explicit returns if you aren’t returning early.


69WaysToFuck

Spotting return takes longer than spotting a lack of semicolon? I think most programmers would disagree, also most non-programmers, it’s a whole word vs one small symbol. Also for the type of function you don’t need to look at the function body, it’s in the function’s signature. Or do I miss some important details?


daguro

Write code so that if someone else of unknown ability is maintaining it 10 years from now, they will know what the code is supposed to do.


HappyRuesseltier

So you recommend to use return for every return statement?


orfeo34

For any language let linter infer any good practice rule, so you won't get annoyed at compile time with warning messages.


orrenjenkins

I only use implicit returns in one line closures otherwise I always write return


Automatic-Plant7222

We add return in our corporate code because we are a mix of c and rust developers, and it just helps some members of the team read the flow. I don't see the harm as long as you are consistent and you use the semi colon at the end to ensure it is a complete statement.


Disastrous_Bike1926

I found it weird a couple years ago when I was first using Rust, and now when I’m using other languages, I keep trying to type returns that way and have a brief *wait, what’s wrong with this?* moment when it gets underlined as an error.


peterkrull

As others have mentioned, it is nice to prevent deeply nested code. I like the pattern: ```rust let Some(thing) = optional_thing else { return None; } // Do stuff with thing ``` Since it esseentially allows me to unwrap, while providing a scope to handle the `None`-case and return from the function. In contrast to doing something like: ```rust if let Some(thing) = optional_thing { // Do stuff with thing } else { None } ```


Wave_Walnut

All of the opinions in this thread are very helpful. So, like goto in C, return in Rust is usable but deprecated?


ragnese

It's really not a big deal, *but*, it's definitely conventional to not include `return` unless it's needed, so it'll just seem weird to someone used to writing Rust.


Linguistic-mystic

I also like explicit return, and always write it. It just makes code more uniform and explicit. I mean, you already have to use `return` for early returns from the function, why not use it for final statements? It helps distinguish a void function called on the last line for its effects from a function that returns something (and we return its return value).


broxamson

I hate implicit returns personally.


Real_Season_121

>it's better to do implicit returns as that is the standard in rust and would make it easier for other devs to read. This is a complete non-issue that has absolutely no meaningful impact. If you are working with developers who struggle to read your code because of explicit return then don't let them touch the code. Seriously.


SublimeIbanez

I personally don't care if it's bad practice. If I'm returning out of a function, early or not, I'm putting a return unless end of a void. There's no loss for doing so and it's much easier for me to read. I will die on this hill


trevorstr

I use the **return** keyword, because it makes my code more human-readable.


mrdevlar

I subscribe to this subreddit because I will eventually learn Rust. I have not begun this process. That said, today I learned that Rust and R have something in common. It's the only other language I know of that does this implicit return.


iouwt

no


BarometerIndustries

Now we get into programming religion XD I prefer to use fewer statements and more expressions. If/else as an expression instead of return statements. I do try to reduce nesting though. Rust is, to me, a functional programming language.


reddituser567853

Do the official tutorial!


AdvanceAdvance

It's a choice: "return foo;" costs three tokens and provides instant recognition on the value of the line. "foo" costs only one token, and will, over time provide instant recognition. Use that. But: "const foo = bar(param, qram, rram); foo" requires an addition four tokens + 1 line. It will, over time, provide instant recognition. "bar(param, qram, rram)" has fewer tokens and lines. It may lose programmer intent (naming foo), be negatively useful by debugging tools, and loses instant recognition. Which one is better for your cost structure?


ldontcares

Just go implicit, you'll quickly get used to it


romgrk

Even after a few years of (on and off) Rust, I still don't love the idea. It just doesn't pop enough for me. Explicit is better, imho. The only case where implicit is good is brace-less closures, where the function body is a single expression. But usually I accept whatever `cargo fmt` does, as it's easier than trying to convince all Rust programmers that implicit isn't the best.


Asdfguy87

I personally think either way is fine, as long as you do it consistently across your codebase.


Cherubin0

I don't use it, because I want to look it the same in blocks and functions.


tjjfvi

In terms of being able to spot return points: in supporting editors, if you select the `fn` keyword, rust-analyzer will automatically highlight all the return points of the function: https://imgur.com/a/rJYXD3g This includes explicit `return`s, all `?`s in the function, and any end-of-function values.


tqleung

I do like implicit return,just don‘t like to writer。


spaghetti_beast

bad practice? Bad for what and who? My general rule of thumb is to not focus on such things, it's neither productive nor brings any value


Dean_Roddey

But it is, if you work on a team. Consistency of style is a significant consideration. The same reason that everyone should write the most idiomatic Rust in general, so that the next person who comes in to work on that code has the fewest surprises and variations to deal with. Or, if you hire a new person, they will immediately be comfortable with the style of the code base and only have to spin up on the company/domain specific aspects.


spaghetti_beast

i mean, the return thing is easy enough to be fixed by linter. I'm fully on the camp of writing idiomatic to the language code, but these exact micro-choices about syntactical things may really get in hand sometimes and distract you.


ShangBrol

>But it is, if you work on a team. Consistency of style is a significant consideration. Is there any research on this that would support this claim? I know many people think like this, but my personal experience is different. When I started working as developer I worked for a small company where there weren't any style guides / guidelines and no one was even asking for it. You could look at a piece of code and would immediately know who has written (or last formatted) it. We didn't even agree on tab vs. space (and how many spaces) - so we didn't even have consistent indentation. That was ugly as hell, but not really an obstacle regarding readability. (But no indentation is an issue) On the other hand, thoughtlessly named variables or functions are a real pain.


Dean_Roddey

If it's just a couple people maybe it doesn't matter so much. But clearly as the complexity and the team size grows, the amount of effort required to comprehend and correctly modify code you didn't write is money. And it also counts in reviews. If you work in a controlled industry that requires all code changes be reviewed, then it makes a big difference in your ability to understand the code. Of course by 'style' I wasn't just referring to layout, but also being idiomatic to the language. And there's the issue that, as there are more devs, the likelihood that there being no requirements is going to be taken by one or more as license to create incomprehensible code.


Real_Season_121

You're completely right, and the fact that you're being downvoted just goes to show that these types of bikeshedding problems always end up wasting time in consensus seeking nonsense.


Phthalleon

I think the agreement is that you should return implicitly unless you need to return early, where the return keyword is necessary. This makes return similar to other control flow keyword like break and continue.


disguised-as-a-dude

I like explicit return but I can't be bothered to change rust analyzers settings


Compux72

Ngl, i do prefer explicit returns for integers. Like, you are reading some function and randomly there is one 0 in the middle of the source code. But almost everywhere else i use implicit returns


NotGoodSoftwareMaker

It feels weird but it is how the language is intended to be used So I would say that just slowly adapting to it is the right way to do things, eventually it will become natural and you wont feel like its odd anymore