How to call return from inside another method?

I want the programmers using ReturnMethod() to be OBLIGATED to return from whichever method they’re calling it. Can that be achieved?

    private void Method1()
    {
        ReturnMethod();
        return; // I don't want to have to write return every time I call this method, I might forget!

        // more code...
    }

    private void ReturnMethod()
    {
        // code...

        // We want that wherever ReturnMethod() is called, it returns
    }

Generally you should generally have only one return statement- at the end of the method.

Also, you don’t have to write return at the end of a void function.

And no, you can’t return from the method above the current one in the stack.

I don’t think you need that return; at all in your example. The return; stops the function. so the //more code… would not get called.

what are you trying to so in the returnmethod? what are you trying to get from it?

That’s exactly the point. So that it doesn’t execute the rest of the function.

I have no idea why you would even want that behaviour… But those methods are marked as “void” which means they have an implicit return. Unless you want to break the control flow then you don’t want a return… just let it do it’s thing. If you do that return, then your “// more code…” will never ever execute.

But as a general practice you should never say “you have to return immediately after calling my method”. Your method shouldn’t know anything about the code that’s calling it or expect any explicit behaviour from that code once it’s job is done.

2 Likes

Don’t put more code there then… your design pattern is fundamentally flawed.

It’s for a state machine where I want that when the ChangeState() is called the rest of the code is not executed anymore

Then there’s no point in the rest of the code even being there. If you don’t want it to be called, put a return, it’s that simple.

There is a point for the code to be there because it’s executed if the condition to change state is not true.

Wherever the ChangeState() method will be called, there will necessarily have to be a return statement right after and if it’s forgotten it will cause bugs/unwanted behaviour.

I’ll show you an example, I’m using several ChangeState() in this method and whenever ChangeState() is called it will always mean that I don’t want to run the rest of the function:

[Update("Attack")]
    private void AttackUpdate()
    {
        if (Interact.Hit)
        {
            Fsm.ChangeState(States.Hit);
            return;
        }

        //ATTACKING
        if (Fsm.TimeInState >= DelayBeforeAttack)
        {
            Sr.StopFlicker();
            Destroy(ExclamationPoint);

            //CHOOSE GROUND ATTACK
            if (DistanceToTarget() < DistanceForJumpAttack
                && HasChosenJumpAttack == false
                && HasChosenGroundAttack == false)
            {
                SpellLastCast = Spell.JumperGroundAttack;
                HasChosenGroundAttack = true;
                AttackManager.Find(Attack.JumperGroundAttack).SetActive(true);
            }
            //CHOOSE JUMP ATTACK
            else if (HasChosenJumpAttack == false
                     && HasChosenGroundAttack == false)
            {
                SpellLastCast = Spell.JumperJumpAttack;
                HasChosenJumpAttack = true;
                AttackManager.Find(Attack.JumperJumpAttack).SetActive(true);
                ProjectileToTarget.Activate(Target.position);
                EnabledGravity = false;
            }

            //GROUND ATK UPDATE
            if (HasChosenGroundAttack)
            {
                if (Fsm.TimeInState >= AttackGroundDuration + DelayBeforeAttack)
                {
                    Fsm.ChangeState(States.Idle);
                    return;
                }
            }

            //JUMP ATK UPDATE
            if (HasChosenJumpAttack)
            {
                Move.TempVelocity = ProjectileToTarget.CurrentSpeed;

                if (ProjectileToTarget.FinishedMovement)
                {
                    Fsm.ChangeState(States.Idle);
                    AttackManager.DisableAllIdentified();
                    return;
                }
            }
        }
    }
[Update("Attack")]
    private void AttackUpdate()
    {
        if (Interact.Hit)
        {
            Fsm.ChangeState(States.Hit);
        }
        else
        {
        //ATTACKING
        if (Fsm.TimeInState >= DelayBeforeAttack)
        {
            Sr.StopFlicker();
            Destroy(ExclamationPoint);

            //CHOOSE GROUND ATTACK
            if (DistanceToTarget() < DistanceForJumpAttack
                && HasChosenJumpAttack == false
                && HasChosenGroundAttack == false)
            {
                SpellLastCast = Spell.JumperGroundAttack;
                HasChosenGroundAttack = true;
                AttackManager.Find(Attack.JumperGroundAttack).SetActive(true);
            }
            //CHOOSE JUMP ATTACK
            else if (HasChosenJumpAttack == false
                     && HasChosenGroundAttack == false)
            {
                SpellLastCast = Spell.JumperJumpAttack;
                HasChosenJumpAttack = true;
                AttackManager.Find(Attack.JumperJumpAttack).SetActive(true);
                ProjectileToTarget.Activate(Target.position);
                EnabledGravity = false;
            }

            //GROUND ATK UPDATE
            if (HasChosenGroundAttack)
            {
                if (Fsm.TimeInState >= AttackGroundDuration + DelayBeforeAttack)
                {
                    Fsm.ChangeState(States.Idle);
                    return;
                }
            }

            //JUMP ATK UPDATE
            if (HasChosenJumpAttack)
            {
                Move.TempVelocity = ProjectileToTarget.CurrentSpeed;

                if (ProjectileToTarget.FinishedMovement)
                {
                    Fsm.ChangeState(States.Idle);
                    AttackManager.DisableAllIdentified();
                    return;
                }
            }
        }
       }
    }

There

Maybe, instead of void, have it return a state.

1 Like

are you asking for something like this.
Check or do some code that sets a value, then check that values state, IE, if a bool is true or false.

private void Method1()
    {
        if(ReturnMethod() == true)
        {
            //do some code if true
        }

    }

    private bool ReturnMethod()
    {
        // code... and set something to true or false

        // We want that wherever ReturnMethod() is called, it returns
        if(something == true)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

That’s not really what I’m looking for johne5 but I’m starting to think it just makes more sense to write return: If methods could return from whichever method they’re called in it might end up being more confusing than helpful.
Thanks for trying to help everyone but I think there’s no good answer to this. Or rather the good answer is to write return.

For a method to be aware of and have control of its calling context is evil. What happens if someone calls the method from another location? What happens if the calling context is changed?

Because of the inherent evilness there is no built in way to achieve the control you are after.

There are several structures you can use to achieve a similar effect.

  • Return a value. Let the calling context resolve dealing with it as appropriate.
  • Set some class level state.
  • Throw an error. This will force the calling context to deal with the error or terminate.

Note throwing errors to control code flow is evil, errors should only be used to indicate actual problems. Search up any of the ‘worst mistakes’ threads I’ve contributed to for a great example.

2 Likes

You can abuse throwing an exception to get that behavior (Kiwasi’s third bullet.) Have the main function catch a fake exception, like “gobacktomain,” and have your returnMethod function always throw it. “Abuse thrown exceptions” has some links to this trick. http://wiki.c2.com/?DontUseExceptionsForFlowControl has partial examples. But note that it says NOT to do that (but then below other people say it’s fine.) One thing for sure, when your programmer friends read your code, they’ll think it’s hilarious.

2 Likes

With statemachines, I’d generally use a coroutine with a while loop that evaluates if the state has changed.

I fixed the whole thing above by adding a simple else block. But this is all getting way beyond the ops intent. He was trying to avoid adding a simple return so he’s not likely to further complicate with conditionals or exceptions, etc. The answer is to just use the return.

1 Like

But that’s fine. It’s sort of the theme in Forums to just let threads be about whatever they want to. As you point out, “how do I organize these nested if/elses?” is the real Q, but it’s kind of boring. I mean, intro textbooks cover it pretty well (OK, many don’t, but mine does and I’m sure lots of others.)

Making a double-return on the other hand, is way more fun. We know it’s just a rabbit-hole the OP went down, but that doesn’t matter. It’s like when you ask for directions, get a partial answer involving the Drive-In, and the locals start discussing who owns it now. It’s no longer your conversation.

1 Like

My intent was to learn how to do double returns and I did!
I might end up using them someday but not this time. Tbh I really like it when people try and solve my question even if it’s not the best programming pattern, better yet if they show a solution and also tell me it’s not the greatest progamming pattern.

I know about if/else’s, however I find returns are clearer in this situation.

1 Like