Scott Thompson wrote:

> When I create the CGRect object I use Data_Make_Struct.  When I want to 
> return the size object out of that rectangle, my thought was to use 
> Data_Wrap_Struct.

Yes.

> The thing that worries me is that the CGSize object I think I want to 
> return from the "size()" method of the CGRect class would be wrapping a 
> piece of the CGRect structure itself.  I'm concerned that should the 
> CGRect be garbage collected that the CGSize object, which is an object 
> wrapper around part of the CGRect's memory, will no longer be valid 
> because the CGRect's memory was reclaimed.

Correct. When the CGRect Ruby instance is garbage-collected, the CGRect 
C struct that it "wraps" will be free'd as well. And that in turn 
invalidates the pointers to its contained CGPoint and CGSize structs, 
even if there are still outstanding Ruby objects that wrap those structs.

> In other words, the pointer to the memory that the CGSize object wraps 
> will be halfway through the memory owned by the CGRect.  I'm worried 
> that the system might dispose of the CGRect not knowing that the CGSize 
> object still needs that memory.

Yes, this is a good thing to worry about ;)

> At any rate, this leads to the following questions:
> 
> First, do I even need to worry about it?  Is the Garbage Collector in 
> ruby clever enough to see that one of my objects has a pointer into the 
> memory that makes up the CGRect object and, therefore, will not release 
> the memory even though the CGRect object itself is not referenced?

No. This is your responsibility.

> If the Garbage Collector is not clever enough to do that, it seems 
> reasonable that the CGRect object might create references to a CGPoint 
> object and a CGSize object within itself...

Not sure I follow you here. Ruby only knows what you tell it about your 
extension module's classes. For example, even though /you/ know that a 
CGRect object contains references to a CGPoint and a CGSize, Ruby 
doesn't deduce that. This is part of the motivation for writing a "mark" 
function for your extension objects; the garbage collector calls that 
mark function to ask, say, your CGRect object what /other/ Ruby objects 
are reachable from there. In your case, you'd want to be sure to call 
rb_gc_mark() for the Ruby objects that are wrapping the CGPoint and 
CGSize objects:

     void mark_CGRect(CGRect *rect)
     {
         VALUE pointObj, sizeObj;
         pointObj = rubyObjectFor(rect->origin);
         sizeObj = rubyObjectFor(rect->size);
         rb_gc_mark(pointObj);
         rb_gc_mark(sizeObj);
     }


> At the same time, however, the CGPoint and CGSize objects want
 > to keep a reference to the CGRect so that its memory won't
 > go away until they are done with it.  Will setting up that kind of
 > circular reference prevent Ruby from being able to garbage collect
 > the rectangle and its point/origin pair?

No, not as long as the mark functions for CGSize and CGPoint mark their 
parent CGRect as still being "reachable". If you still have some 
outstanding references to the point or size objects for a given 
rectangle, their mark functions will get called and thus the rectangle 
won't get garbage-collected.

Yes, it is a little complicated ;)

Hope this helps,

Lyle