tags:

views:

173

answers:

6

Hi All,

I have a piece of code which I am doubting it as a implementation of recursion by its definition. My understanding is that the code must call itself, the exact same function. I also question whether writing the code this way adds additional overhead which can be seen with the use of recursion. What are your thoughts?

class dhObject
{
public:
   dhObject** children;
   int numChildren;
   GLdouble linkLength; //ai 
   GLdouble theta; //angle of rot about the z axis
   GLdouble twist; //about the x axis
   GLdouble displacement; // displacement from the end point of prev along z
   GLdouble thetaMax;
   GLdouble thetaMin;
   GLdouble thetaInc;
   GLdouble direction;

   dhObject(ifstream &fin)
   {
      fin >> numChildren >> linkLength >> theta >> twist >> displacement >> thetaMax >> thetaMin;
      //std::cout << numChildren << std::endl;
      direction = 1;
      thetaInc = 1.0;
      if (numChildren > 0)
      {
         children = new dhObject*[numChildren];
         for(int i = 0; i < numChildren; ++i)
         {
            children[i] = new dhObject(fin);
         }
      }
   }

   void traverse(void)
   {
      glPushMatrix();
      //draw move initial and draw
      transform();
      draw();
      //draw children
      for(int i = 0; i < numChildren; ++i)
      {
         children[i]->traverse();
      }
      glPopMatrix();
   }

   void update(void)
   {
      //Update the animation, if it has finished all animation go backwards
      if (theta <= thetaMin)
      {
         thetaInc = 1.0;
      } else if (theta >= thetaMax)
      {
         thetaInc = -1.0;
      }
      theta += thetaInc;
      //std::cout << thetaMin << " " << theta << " " << thetaMax << std::endl;
      for(int i = 0; i < numChildren; ++i)
      {
         children[i]->update();
      }
   }

   void draw(void)
   {
      glPushMatrix();
      glColor3f (0.0f,0.0f,1.0f);
      glutSolidCube(0.1);
      glPopMatrix();
   }

   void transform(void)
   {
      //Move in the correct way, R, T, T, R
      glRotatef(theta, 0, 0, 1.0);
      glTranslatef(0,0,displacement);
      glTranslatef(linkLength, 0,0);
      glRotatef(twist, 1.0,0.0,0.0);
   }
};
+5  A: 

Yes, since you have certain functions calling themselves. By definition that is direct recursion. You could also have indirect recursion if you had function A() calling function B(), function B() in turn (directly or indirectly) calling function A() again.

sharptooth
Are they really calling **themselves** though?
IVlad
Where does he have functions calling themselves? He has another object that calls this function, but it is not `this->callMyFuction()`.
Shaihi
In this case - yes, they are actually calling themselves, since *this* is of type `dhObject*`.
sharptooth
My C++ is not great, but even if the same exact function is called, it's called as part of a different object, so it doesn't really call itself as far as I can see.
IVlad
Same object, but different instance. Does not that make a difference? - I can see why he is asking now...
Shaihi
The constructor is calling itself through `new dhObject`. `update` calls `update`, the same for traverse. Basically, whenever you define something (eg. function `update()`) in terms of the same object, you have recursion.
jpalecek
Every member function has an implicit *this* parameter. So although it is called as `functionImpl( someOtherInstance, parameter )` instead of `functionImpl( thisInstance, parameter )` is still calls *itself*, just the implicit parameter differs.
sharptooth
Thanks sharptooth for your explanation. Would you see potential overhead caused by using this for something that might be small (4 dh objects each with 1-2 other dh objects)? Would the g++ compiler not attempt to optimise this into a loop?
dekz
@dekz: In order to find whether the optimization takes place you need to examine assembly code emitted. Using recursion with small depth is usually okay - overhead will be minimal, however the code will not be adaptable to biffer input - once the input is too big it will incur stack overflow and just crash.
sharptooth
+1  A: 

Recursion only occurs when your function calls itself. In your case, they aren't the same functions. traverse() calls traverse() for its children, and not itself.

In your example,

parent->traverse()

does not call itself. Instead, it calls

parent->children[i]->traverse()

so parent->traverse() really gets executed just once. This is the same with your update() method.

maranas
There are no `parent->traverse` functions in C++. There is only `dhObject::traverse`.
jpalecek
you are correcting the syntax but you did not seem to comment on the relevance of the answer to the question. i could have put in pseudocode to make my point. also, is it still invalid if parent was a pointer to a dhObject??
maranas
@maranas, actually, he did comment on the relevance. there is a single function, it calls itself. That function is dhObject::traverse. The distinction you're making based on the object is not a distinction that c++ makes.
Bahbar
+6  A: 

This is a matter of definition/nitpicking. In this C function:

void traverse( tree * t ) {
    if ( t != 0 ) {
        traverse( t->right );
        traverse( t->left );
    }
}

Is the function recursive? I would say yes, even though it is being called on different objects. So I would say your code is also recursive. To take an even more extreme example:

unsigned int f( unsigned int n ) {
    if ( n = 0 ) {
       return 0; 
    }
    else {
       return f( n - 1 );   // XXX
    }
}

The thing the function is being called on at XXX is obviously not the same thing it was originally called on. But I think everyone would agree this is a recursive function.

anon
for the definition of recursion it does not matter on which object the function is called or which parameters are passed. The only constraint is that you have to (directly or indirectly) call the same function again before you leave it.
codymanix
I agree that your examples are recursive, but in my example, the functions exist in an entirely different object. Your example calls the exact same function, mine calls a function in a different object. Isn't the definition of recursive behaviour to call the exact same function?
dekz
@dekz No they don't. In C++, functions belong to the class, not to objects.
anon
@Neil, Oh I see, so the both functions are stored at the same memory adress? a->traverse() and b->traverse() would have the same memory address? If not then they semantically the same function?
dekz
@dekz There is no "both" there is only one function "traverse" which exists at a single unique address. There are multiple calls to this function, but a function call is not a function.
anon
A: 

Calling one of these methods(traverse or update) will have the effect of calling that same method an every child. So, the methods are not recursive. Instead, it's a recursive algorithm: it is applied recursively on the logical tree of objects.

The depth of the call stack is directly determined by the structure of the data on which the algorithm operates.

What really happens is this(pseudo code):

Function Traverse(object o)
{
   [do something with o]

   Foreach(object child in o.Children)
       Traverse(child);

   [do something with o]
}
Andy
+1  A: 

Looks like recursion in the traverse() and update() methods with depth controlled by the physical geometry of your object collection.

If this is your actual class I would recommend a few things:

  1. Check the upper bound of numChildren before using it lest someone passes in a remarkably huge number by mistake.

  2. If this will be used in a threaded environment you might want to synchronize access to the child objects.

  3. Consider using containers instead of allocating an array. I don't see a destructor either so you'd leak the memory for the array storage and the children if this object gets deleted.

Amardeep
part of the object including the destructor was snipped as it wasn't relevant.
dekz
+1  A: 

If all you're worried about is the overhead of recursion then the important thing is to measure how deep your stack goes. It doesn't matter whether you're working recursively or not, if your stack is 100 calls deep.

Skilldrick
It's about 4 total objects, each with 1-2 children. So I don't think there would be excessive overhead. Would you agree?
dekz
Yes. The only problem with recursion is when you go really deep.
Skilldrick