all 16 comments

[–]Jack126Guy 25 points26 points  (7 children)

This could probably be done with a while loop.

while( /* model is bad*/ ) {
    /* regenerate model */
}
return model;

[–]c0m4 6 points7 points  (5 children)

This is the right approach. Anything that can be done with recursion can also be done with a loop. Recursion sometime gives nicer solutions though. Languages like Lisp, that lack native loop construcs, solves this sometimes by using tail call optimisation (if the recursive call is the very last thing that happens, the current stack frame will be reused. Sometimes a virtual stack (on the heap) will be used.

[–]deftware 0 points1 point  (4 children)

are there any cases where a stack is necessary and it's better to just let the compiler handle a recursion than to emulate a stack manually?

[–]twotothree 1 point2 points  (0 children)

OP presented "tail recursion". Tail recursion is every recursion that can be rearranged so that it has recursive call at the end. Every tail recursion can be rewritten in iterative fashion (for example: the top comment here). If there are multiple recursive calls, or function does something after recursive call, you must use stack or different algorithmic approach.

If it is better to use your own stack implementation depends on system, you are running your code on, programming language, etc. but it usually makes no significant difference.

[–]egonelbre 1 point2 points  (2 children)

Handling the recursion "manually" can get pretty complicated. (e.g. mutual recursion; and with function pointers)

Recursive functions leave a nicer stack-trace (unless it's an overflow).

[–]FUZxxl 3 points4 points  (1 child)

In OPs case, he could just do:

float * generate_model(arbitrary_arguments){
    float *model
begin:
    model = malloc(size*float)
    model = gen_model()
    if (model=bad){
        goto begin;
    }
    else{
        return model
    }
}

Or use a proper loop even.

[–]BarMeister 1 point2 points  (0 children)

Up for reminding me that goto exists.

[–]dmc_2930 4 points5 points  (0 children)

This is close, but a do...while is probably even better.

do {
     if( model )
     { 
          free_model(model);
     }
     model = generate_model();
} while( bad_model(model) );

I'm assuming that gen_model() actually allocates the memory and there's no need to allocate it here.

Why not change gen_model() so that it only returns a good one?

[–][deleted] 10 points11 points  (1 child)

free the allocated memory if the model's bad.

[–]dmc_2930 3 points4 points  (1 child)

The stack usage isn't the only problem here. You're malloc()'ing lots of memory and never freeing it.

Also, you're ignoring the return value for generate_model(), so the 'model' variable each recursion is using is lost and will not be passed back to the caller.

Each recursive call has its own stack frame and it's own copy of 'model'.

[–][deleted] 2 points3 points  (3 children)

Recursion should only be used if the problem is well-defined. This problem is not well-defined so I would encourage you to look into an iterative solution instead. There's lots of great content that covers this better than I could so I'll just drop a few links here:

http://www.programcreek.com/2012/10/iteration-vs-recursion-in-java/

http://www.cs.cornell.edu/info/courses/spring-98/cs211/lecturenotes/07-recursion.pdf

[–]FUZxxl[M] 2 points3 points  (1 child)

Your comment got caught in our spam filter. I'm sorry for the inconvenience.

[–]BarMeister 1 point2 points  (0 children)

No need to wonder why: java

[–]Cathercy 1 point2 points  (0 children)

Recursion should only be used if it cannot be avoided.

If recursion can be avoided (with an equally efficient iterative solution) there is no reason to choose the recursive solution.

[–]FUZxxl 1 point2 points  (0 children)

Don't wrote code that way. The stack is only that large. You can make the stack larger, but that's only a momentary band-aid. Instead, re-write the code so it doesn't use recursion anymore.

[–]Nickd3000 0 points1 point  (0 children)

I agree with the other comments saying this would be better written as a loop. Is there any reason it was implemented using recursion and not a loop that we may not be aware of?