LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Function design, 1 return-statement? (https://www.linuxquestions.org/questions/programming-9/function-design-1-return-statement-635763/)

raskol 04-16-2008 10:53 AM

Function design, 1 return-statement?
 
btw noob-question, is return considered a statement?

is it good design to have only one return per feunction if possible or it doesnt matter?

which is better:

Code:

def power(nbr, power):
    if power >= 1:
        acc=nbr
        for x in range(1, power):
            acc=acc*nbr
        return acc
    if power == 0:
        return 1
    if power < 0:
        acc=1
        x=power/-1
        while x > 0:
            x=x-1
            acc=acc/nbr
        return acc

or

Code:

def power2(nbr, power):
    acc=1
    if power >= 1:
        acc=nbr
        for x in range(1, power):
            acc=acc*nbr
    if power < 0:
        acc=1
        x=power/-1
        while x > 0:
            x=x-1
            acc=acc/nbr
    return acc

the second one is shorter obv but if u could construct a scenario where it is the same anyhow, better to have only 1 return?

raskol 04-16-2008 11:10 AM

Code:

def power3(nbr, power):
    acc=1
    if power >= 1:
        acc=nbr
        for x in range(1, power):
            acc=acc*nbr
    if power < 0:
        if nbr!=0:
            acc=1
            x=power/-1
            while x > 0:
                x=x-1
                acc=acc/nbr
        else:
            return "Division by zero"       
    return acc

or

Code:

def power(nbr, power):
    if power >= 1:
        acc=nbr
        for x in range(1, power):
            acc=acc*nbr
        return acc
    if power == 0:
        return 1
    if power < 0:
        if nbr!=0:
            acc=1
            x=power/-1
            while x > 0:
                x=x-1
                acc=acc/nbr
            return acc
        else:
            return "Division by zero"


any idea how to use only 1 return statement in power3?

graemef 04-16-2008 05:56 PM

There is no correct answer to this. However there is a school of thought that it is good practice to minimise the points of exit from a function. Thus power() has three exit points whilst power2() has just the one, so power2() is thought by some to be "cleaner".

The problem arises with the example you provided with power3() where you are returning different data types. This is solved in strong typing languages by the use of exceptions. A construct that has been adopted by many weak typing languages as well. It's advantage is that in normal running you know what will be returned (and in the case of power2() where), however when something unexpected occurs, for example division by zero, then you immediately jump out of the function and let the exception handler take control.

SciYro 04-16-2008 08:24 PM

Schools of thought have no real place in practice. Use the style that makes the code cleaner to read. If its more natural to have 1 return, have 1 return. If its more natural to have 100,000,000,000 returns, you have no clue how to design code. If its more natural to use 10 returns, use 10 returns.

Such schools of thought like "thats minimize this" or "don't use that" are based solely on theory, and in practice, usually makes code harder to read because you have to bang a function into shape using to use a un-natural methodology.

graemef 04-16-2008 10:00 PM

Quote:

Originally Posted by SciYro (Post 3123590)
Schools of thought have no real place in practice.

On the contrary where would we be without schools of thought, goto ghetto most likely? ;)


The "theory" behind minimising the number of returns revolves around trying to make it easier to understand the flow of control in a large program. As you suggested excessive number of returns is most likely the result of poor design. Since the same school of thought suggests that functions should be small compact beasts that perform a single task it is normally easy to restrict the number of returns when following that ideology. But as I said there is no correct answer. There are of course opinions aplenty :)

Dan04 04-16-2008 11:55 PM

One thing that is definitely bad style, however, is this:

Code:

def power(nbr, power):
It's not a good idea to give a function argument the same name as the function. Especially if you want to make recursive calls.

Dan04 04-17-2008 12:02 AM

One approach that follows the letter, although not necessarily the spirit, of having only one return statement is:

Code:

class Return(Exception):
    pass

def power(nbr, exponent):
    try:
        if exponent >= 1:
            acc = nbr
            for x in range(1, exponent):
                acc = acc * nbr
            raise Return()
        if exponent == 0:
            acc = 1
            raise Return()
        if exponent < 0:
            acc = 1
            x = exponent / -1
            while x > 0:
                x = x - 1
                acc = acc / nbr
            raise Return()
    except Return:
        return acc


Dan04 04-17-2008 12:08 AM

A more elegant solution:

Code:

from __future__ import division

def power(base, exponent):
    """Equivalent to base ** exponent where exponent is an integer."""
    neg_exp = exponent < 0
    if neg_exp:
        exponent = -exponent
    result = 1
    for index in xrange(exponent):
        result *= base
    if neg_exp:
        result = 1 / result
    return result

Note that by starting the loop from 0 instead of 1, x**0 doesn't need to be a special case. Also, rather than have two separate loops, just use the identity x**(-y) == 1/x**y.

jlinkels 04-17-2008 07:24 AM

It is not the number of returns in a function. It is how there are placed and used.

It is said (again such a rule of thumb) that a function should not be longer that the size of a piece of paper, that is about 60 lines. Now since we never use paper anymore (don't we?) it is easier to have a function grow without noticing. My functions are usually anything between 10 and 200 lines.

Now in such a 100+ lines function, I consider it bad to hide some returns randomly and deeply embedded in the algorithm. In that case it is (a) hard to follow the program flow (b) difficult to see what value is returned in that stage of the program.

On the other hand, to perform a number of tests or simply calculations at the start of the function, which all result in a return doesn't matter at all, even if you have 10 of such cases.

Neither should it be a problem if at the entrance of a function the program flow splits into a number of blocks (with a case statement for example) and each block is exited directly with a return.

On the the contrary, such a construct might be much better than a design following the text book and create an artificial single exit point with complicated if-then-else constructs.

Tell you something. When I write functions with multiple decision points where I have to exit, but all exits require the same piece of common code (like releasing a semaphore), I use a GOTO to get there. Yes! Code unreadable? NO! Not as long as your goal is to design readable code.

jlinkels

jtshaw 04-17-2008 07:55 AM

From the prospective of a guy that largely does C and C++ development, it is usually resource management that causes me to always use only 1 return from a function. If I had a nickel for every memory leak I have fixed because somebody allocates memory and returns in a conditional which doesn't free said memory I'd be a very rich man. With functions that have to do several allocations you end up having to do several frees with your return so it quickly becomes annoying to do anything other then a single point of return. Because I'm so conscious of this I find pretty much every function I design ends up with a single point of return. This, of course, is not really an issue in languages that are garbage collected.

jlinkels 04-17-2008 09:52 AM

jtshaw:

That was the other reason for that common piece of code I mentioned to be executed before a return. How could I ever forget to mention freeing memory? :)

jlinkels


All times are GMT -5. The time now is 10:28 PM.