Welcome to the Second Life Forums Archive

These forums are CLOSED. Please visit the new forums HERE

When to use 'return'?

Debbie Trilling
Our Lady of Peenemünde
Join date: 17 Oct 2006
Posts: 434
12-19-2008 02:45
Hi

I'm interested in hearing opinions/facts about the use of 'return;'. Specifically, the use of a series of returns as opposed to using an IF-ELSE statement.

EG:

if (variable == 1) { do_one(); return;}
if (variable == 2) { do_two(); return;}
if (variable == 3) { do_three(); return; }
do_four();

as opposed to

if (variable == 1) { do_one(); }
else if (variable == 2) { do_two(); }
else if (variable == 3) { do_three(); }
else { do_four(); }

I recently read a claim that the 'return' method was preferable to the IF-ELSE. This may well be correct, I really don't know. I hope to learn if it is true or not from this thread.

FWIW, I come from a school of thought that avoids using GOTO's under almost any circumstance (and certainly where the code can be structured to avoid their use) and in the former example it seems to me that 'return' is effective being used as a GOTO. However, the wiki shows an example of 'return' being used in a similar way.

I am currently only using 'return' when actually returning a value, for example:

integer DoMaths(integer Input)
{
integer Output = Input + 1;
return Output;
}

Over to you...what are the pros and cons of each method? Is one preferable over the other or do they both have equal merit?
_____________________
http://wiki.secondlife.com/wiki/User:debbie_Trilling
Nexii Malthus
[Cubitar]Mothership
Join date: 24 Apr 2006
Posts: 400
12-19-2008 03:03
In your code the return wasn't included into the if code, so it would have skipped all the other checking..

Return has a few different purposes.

In functions it allows you to stop the execution of the routine as well as, primarily for, returning a solution/value.

Return in event code is just useful if you want to avoid running any further code, such as after an entire if-else block..

For example:

code1
code2
if( ... ){ Func1(); return; }
else if( ... ){ Func2(); return; }
else if( ... ){ Func3(); return; }
code3
code4

if any of the if statements do manage to run, code3 and code4 will never run, because the execution of the flow would have ceased and basically skipped code3 and code4.

Also Goto/Jump has been really useful to me in loops. It is an absolute lie that goto should never be used, it is just that most code won't need it. But for some exceptions it is the difference between efficient code and lagging the simulator to hell for absolutely no reason whatsoever. For example Search, such as pathfinding, or searching through a List, or some other graph are applicable uses for preventing further iterative searching if a solution has already been found.

As to your original question of the differences between
if( ... ){ func1(); return; }
if( ... ){ func2(); return; }
if( ... ){ func3(); return; }
and
if( ... ){ func1(); }
else if( ... ){ func2(); }
else if( ... ){ func3(); }

The only differences I see are primarily aesthetic. But the first method would prevent any further code from running, which might be preferable in a function actually.

I think we might need an expert on the compiled code such as Strife to explain the core differences of performance and size.
_____________________

Geometric Library, for all your 3D maths needs.
https://wiki.secondlife.com/wiki/Geometric

Creator of the Vertical Life Client
Dora Gustafson
Registered User
Join date: 13 Mar 2007
Posts: 779
12-19-2008 03:08
You probably mean:
if (variable == 1) { do_one(); return;}
if (variable == 2) { do_two(); return;}
if (variable == 3) { do_three(); return;}
Otherwise test 2 and 3 are never executed:)

I myself don't care much about using returns in 'case' like structures.
If I have many tests I rather divide the block in half's, fourth's, eight's etc.
That way you can find a specific case in a few jumps.
Of course this can only be done if the values tested against can be ordered.
_____________________
From Studio Dora
Debbie Trilling
Our Lady of Peenemünde
Join date: 17 Oct 2006
Posts: 434
12-19-2008 03:25
From: Dora Gustafson


You probably mean:
if (variable == 1) { do_one(); return;}
if (variable == 2) { do_two(); return;}
if (variable == 3) { do_three(); return;}
Otherwise test 2 and 3 are never executed



From: Nexii Malthus


In your code the return wasn't included into the if code, so it would have skipped all the other checking..



Both correct. Well spotted, that is exactly what I meant. Am so *not* used to using returns in this way!

Original post now corrected
_____________________
http://wiki.secondlife.com/wiki/User:debbie_Trilling
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-19-2008 06:58
Both are fine; it's a stylistic difference.

Return is not the same as "the evil goto" in terms of violating structure. (That said, there is a time and place for goto, though I very rarely use it, and I've been writing code that has to be extremely optimized, since it handles every packet forwarded by a high speed internet router linecard, where every nanosecond counts.)

In general, I like to use early returns to handle special cases, to simplify the logic of a function (or, in LSL, a state handler). Find the special case, handle it completely, return, and forget about it for the rest of the function. This has two advantages over fully-block-structured code (as advocated by the academics):

1) The logic is much more linear and easier to follow. The code doesn't get indented to the right with each special case test (usually in RL code, tests for error conditions). It's far easier to understand the context of code that's not deeply indented.

2) Code that handles special cases is close to the test for the special case. In pure block structured code, the usual convention is to test for a special case (usually an error) and handle the non-special or error-free case in the "then" clause. By the time we get to the "else" clause, we've forgotten what the test was and have to scroll back.

But in the case of the regular list above, the only advantage to the "return" is that for lists with more than 15 or so tests, you won't hit the compiler limitation on cascaded if-then-else. (IIRC it's about 15, and who knows, it may have been fixed.)

The disadvantage with using return is simply that when using that form, I often add a new case and forget the return, leading to a bug the first time I test it -- usually easily recognized and fixed. But it's far less likely to make the same mistake with cascaded if-then-else.

IMHO, as alluded to above, you should choose one or the other based on what is likely to happen BELOW the cascade. If there's nothing, then the two are equivalent. If there is code, the two are very different, so use the one that applies. If you use the 'return' method but then find there's something common to do for all cases, you'll want to recode it as cascading if-then-else.

IMHO, those who say that 'return' is just a goto in disguise are misled. Here's what happened. There was a lot of research comparing pure block structured code to unstructured code, and block structured code won hands down. Return statements violate pure block structure rules, so the obvious implication is that they're bad. Wrong. I always ask dvocates of banning early returns to point to any research studying pure block structure versus structured use of early returns, and they always say "I'll get back to you", but never do. In my professional experience, however, I've mentored dozens of new recruits (of all experience levels), getting them to unlearn what their professors have mistaught them about this. While I didn't do any scientific studies, the results are quite clear that careful use of early returns leads to clearer code with fewer bugs.

It's an uphill battle trying to get dogmatic academics to admit it, though. (By definition, of course ;) )
Argent Stonecutter
Emergency Mustelid
Join date: 20 Sep 2005
Posts: 20,263
12-19-2008 07:08
As far as efficiency goes, there might be a Strife-level performance inprovement from saving the extra branch to the final return in the function, but in practice it's unlikely to help.

Stylistically, I use returns to simplify code.


if(rare case) return;

stuff;

if(stuff failed) return;

more code...


is easier on the eyes than:

if(!rare case) {
...stuff;
...if(stuff succeeded) {
......more code...
...}
}

But sometimes it isn't. Programming is an art as well as engineering.
_____________________
Argent Stonecutter - http://globalcausalityviolation.blogspot.com/

"And now I'm going to show you something really cool."

Skyhook Station - http://xrl.us/skyhook23
Coonspiracy Store - http://xrl.us/coonstore
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-19-2008 08:10
I would suggest 'else if' for this kind of thing rather than 'if' in many cases even if each branch contains a return. It shows the reader the intent and makes it clear that the branches should be mutually exclusive even if at some future date some processing has to be done after some or all of them by removing the returns.
Scott Savira
Not Scott Saliva
Join date: 10 Aug 2008
Posts: 357
12-19-2008 09:53
For the purpose you are demonstrating, I would say that the "If-Else If" method is more traditional and easier to read and comprehend quickly. As long as they are used to the exact same effect, I don't really see people use returns in that fashion very often.
Escort DeFarge
Together
Join date: 18 Nov 2004
Posts: 681
12-19-2008 11:09
From: Argent Stonecutter
As far as efficiency goes, there might be a Strife-level performance inprovement from saving the extra branch to the final return in the function

History take note of the first recorded use of the term "SLPI" (Strife-Level Performance Improvement).

/esc
_____________________
http://slurl.com/secondlife/Together
Sindy Tsure
Will script for shoes
Join date: 18 Sep 2006
Posts: 4,103
12-19-2008 11:35
From: Debbie Trilling
I'm interested in hearing opinions/facts about the use of 'return;'. Specifically, the use of a series of returns as opposed to using an IF-ELSE statement.

/me cues the religious battle!

In general, functions with a single exit are inherently less complex (which == easier to test, which == more stable) than functions with multiple exits. Google up 'code complexity metrics' or 'cyclomatic complexity' for some long, painfully detailed discussions on this. Start with lots and lots of free time and a big tin of aspirin.

I usually stick to smallish, single purpose functions with a single exits, unless there's some real need to do otherwise. People with strong OOP backgrounds also probably do this while people who were raised on non-OOP languages won't cringe as much at the thought of a stray goto or return in the middle of a function.

All that said, your best bet is to do whatever makes things easiest for you to maintain your code. It's not really worth the effort of doing the 'correct' thing if your own code makes you go crosseyed and doesn't really work well. That's really the end goal which trumps almost everything else: code that works.
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-19-2008 12:49
From: Sindy Tsure
/me cues the religious battle!

In general, functions with a single exit are inherently less complex (which == easier to test, which == more stable) than functions with multiple exits. Google up 'code complexity metrics' or 'cyclomatic complexity' for some long, painfully detailed discussions on this. Start with lots and lots of free time and a big tin of aspirin..
Discussions and metrics based on invalid assumptions drawn from inadequate research ...
Lear Cale
wordy bugger
Join date: 22 Aug 2007
Posts: 3,569
12-19-2008 12:56
The number of paths through the two examples in the OP are the same, so your generalization doesn't apply in this case. One is not simpler than the other.

I detest seeing this overgeneralized argument used again and again to vilify a practice that dramatically increases code clarity.

Returns used willy-nilly do indeed increase complexity and obfucation, so the generalization is a valid one when applied to returns used without any kind of structure. If you restrict them to the first indentation level, the generalization doesn't apply because it doesn't increase the number of paths.
Hewee Zetkin
Registered User
Join date: 20 Jul 2006
Posts: 2,702
12-19-2008 14:45
Yeah. It's true a lot of returns can complicate things, but so can a lot of logic to get around reasonable use of returns. For example, precondition checks at the beginning (and sometimes middle) of a function are an excellent place to put them IMO because otherwise you're going to need to encapsulate the rest of the function's code in conditional logic. It doesn't apply to SL, but 'finally' type constructs (Java has them and if IIRC C# does too) decrease the "cost" of returns. My advice would personally be to use them where it logically makes sense (e.g. you KNOW the work of the function is done and it doesn't make sense to do any more processing), but don't work really hard to either use them more or less often than that (i.e. don't worry about their "efficiency";).
Void Singer
Int vSelf = Sing(void);
Join date: 24 Sep 2005
Posts: 6,973
12-19-2008 17:16
personally I find they see their bext use as exceptions. if you're using a bunch of them together, it's usually an indication that either your testing logic is flawed, or your flow logic is flawed.

for instance, if the standard case for your testing leads to a return, with one or two cases handled by folow up code, that follow up code should probably be encapsulated in a function, or your testing logic reversed (if possible).

you usually want to try to avoid doing returns if you only want to shorcut a linear series of tests, unless they are arranged in order of likelyhood (and even then you can usually reorder the tests to be more efficient and naturally skip unneeded further tests)
_____________________
|
| . "Cat-Like Typing Detected"
| . This post may contain errors in logic, spelling, and
| . grammar known to the SL populace to cause confusion
|
| - Please Use PHP tags when posting scripts/code, Thanks.
| - Can't See PHP or URL Tags Correctly? Check Out This Link...
| -