2

So if I have a big function I break it to smaller ones to increase readability.

If I have parts in my big function where I want it to return. I want my subfunctions to have the ability to make the main function terminate as well, if a condition is true in the subfunction. What's the best approach for this?

Making subfunctions return a bool variable seems messy with the too many ifs in the main function.

OriginalFunction

void MainFunction()
{

    //DoStuff1
    ....
    ....
    if(condition1)
        return;

    //DoStuff2
    ....
    ....
    if(condition1)
        return;

    //DoStuff3
    ....
    ....
    if(condition1)
        return;

    //DoStuff4
    ....
    ....
    if(condition1)
        return;

}

Modified Function

void MainFunctionModified()
{
    if(DoStuff1())
        return;

    if(DoStuff2())
        return;

    if(DoStuff3())
        return;

    if(DoStuff4())
        return;

}

bool DoStuff1()
{
    ....
    ....
    if(condition1)
        return true;

    return false;
}
  • To be honest, your "modified" version is very readable. I would just go with that. – Greg Burghardt Jul 10 '18 at 16:16
4

If the language you are using uses lazy evaluation of expressions, then you can just link those sub functions with &&'s. It'll then end the expression evaluation, and thus the function calling, on the first false that's returned:

void MainFunctionModified()
{
    DoStuff1() &&
    DoStuff2() &&
    DoStuff3() &&
    DoStuff4();
}

bool DoStuff1()
{
    ....
    ....
    return condition1;
}

...
  • Considering the question as asked, it's hard to imagine a better answer. – OldFart Jul 10 '18 at 15:39
2

Another option would be to let the submethods throw exceptions that propogate to the caller. This isn't a good fit all the time, but if the submethods are only operating by being called from the main method (and not part of a larger network of classes), it could work and is easier to implement (and read, I think) than the ICommand suggestion:

public void main() {

    try {
        sub1();
        sub2();     
        // finalize as if all were successful
    } catch (Exception e) {
        // do whatever
    }   
}

private void sub1() {
    //...
    throw new InvalidOperationException();
}

private void sub2() {
    //...
    throw new InvalidOperationException();
}

In both the ICommand suggestion and the chained-and suggestion, these rely on the submethods returning a status (bool) depending on whether the method was successful. Myself, I tend to avoid returning like that and prefer to assume the method was successful unless there's an exception thrown.

1

Your function could benefit from implementing the command pattern, or at least a simplified version of it.

You'll have to create an "ICommand" interface (I'll be using C# notation since I'm more fluent with it)

public interface ICommand
{
    bool Execute();
}

And then implement each command class with one of the parts you want executed. Then, in your main function, you'll have:

void MainFunction()
{
    var commands = new List<ICommand>
    {
        //initialize command classes here, or have another method return a command list
    }
    foreach(var command in commands) 
    {
        if (!command.Execute()) return; //you can also break out of the foreach, roll back, or do other actions in case of failure
    }
}

You can also take a more slim and functional approach to the above method, although less flexible since you don't have an expandable interface:

void MainFunction()
{
    var functions = new List<Func<bool>>
    {
        //initialize with a list of function delegates here
    }
    foreach(var function in functions) 
    {
        if (!function()) return;
    }
}
0

With most languages, a function must always return to the caller. Typically, if you need the program to terminate without the caller continuing after the function call, the function will return a value and the caller will check for it, as you are doing in your example.

Some languages also offer a direct way to terminate the process (for example, .NET programs can use Environment.Exit()), but this is usually not the best way to do it.

-1

From your OriginalFunction, If your DoStuff operations represent the behaviors your MainFunction() is expected to execute in their own conditions. With that many branches, you might consider using the State Pattern.

The State Pattern effectively reduce the complexity of branching strategies and make the code more readable and maintainable.

-1

This is one of the reasons C included the setjmp/longjmp functions: Unwind a call stack of considerable depth. This approach does, however have some dangers of its own - if something in the call chain did a considerable resource allocation, that resource might be leaked, so must be handled with care.

Other languages have language components similar to setjmp/longjmp.

Another approaches could be a typical state machine structure:

while (state  != STATE_EXIT) {
   switch (state):
      case FUNC1:
         state = doFunc1();
         break;
      case FUNC2:
         state = doFunc2();
      ...
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.