Storing a reference to an object ...

BlitzMax Forums/BlitzMax Programming/Storing a reference to an object ...

The r0nin(Posted 2005) [#1]
I have a conceptual problem, and I can't figure out the most effective way to do it. I have two objects of the exact same type, but I want one to be the "parent" of the other, so that when I manipulate one object I can then call back and perform functions on the parent as well.

In short, when I create the "child", I want the "parent" to become inactive (through a flag setting). When the child has finished doing what it is going to do, I want it to reactivate (through the same flag) the parent.

I thought of creating parent/child lists, but iterating through lists to find a single object seemed inefficient. I also considered using pointers, but I'm not comfortable enough with how Blitz handles memory to be sure of the form. This is the kind of thing I wanted to do:
'-----------------------------------------------------------
'***********************Widget Type ************************
'-----------------------------------------------------------

Type Widget
	Field Name$ = Null
	Field Uses =0
	Field pos_x,pos_y
	Field Is_child = False
	Field Parent:Widget Ptr = Null
	Field Is_Active = True
	
	Global WidgetList:TList
	
'*************************Create****************************

	Function CreateWidget:Widget(temp_name$,x,y,num_uses)
		temp_widget:widget = New widget
		temp_widget.name = temp_name
		temp_widget.pos_x = x
		temp_widget.pos_y = y
		temp_widget.uses = num_uses
			If WidgetList=Null Then WidgetList = CreateList()
		WidgetList.AddLast(temp_widget)
	Return temp.widget
	End Function

'***********************Make Widget a child of another **************

	Method MakeChild (in:widget Ptr)
		Is_child = True
		parent = in
	End Method
	
'********************** Where the Widget does stuff, and where it turns off the parent!!!!!
	
	Method DoStuff()
	
		Var Parent.MakeInactive() 'This is where I try to make the parent object inactive but
								  ' it doesn't work.  I need to know either how to make the 
								  ' pointer able to refernce the method of the object or a 
								  ' better way to do this!
		
		......  Do other stuff .... 'All the rest of the programming.
		
		Var Parent.MakeActive() ' Same issue...
		
	End Method

' ********************* Sets Flag to active ************************

	Method MakeActive ()
		Is_active = True
	End Method

'***********************Sets flag to inactive ********************

	Method MakeInactive()
		Is_active = False
	End Method

End Type

'----------------------------------------------------------------
'******************** Starts the main program *******************
'----------------------------------------------------------------

Global thing1:widget = Widget.CreateWidget ("First",1,1,0)
Global thing2:widget = Widget.CreateWidget ("Second",1,1,0)

thing2.MakeChild(Varptr thing1)
thing2.DoStuff() '<----------------- The parent should be inactive While this is happening


Any suggestions are welcome. I'd really rather avoid pointers altogether, but I can't think of any other way that doesn't involve looking through a "ParentList" or ChildList" etc...


N(Posted 2005) [#2]
Why are you using pointers here in the first place?


The r0nin(Posted 2005) [#3]
Well, I couldn't create a widget field in a widget type to store the widget, etc... (good old recursive declarations).

This shouldn't work:
Type widget
     Field Parent:widget new widget


So I tried to find another way to store the location to the parent. Perhaps it would work without the "new widget", but I ended up going with a "ParentList:TList", because I realized one case where I might have to have more than one parent. I'm still curious if there is another (more efficient) way to store a parent, though. Besides, I could use some practice/experimentation with pointers and pointer references to variables, anyway...


Bot Builder(Posted 2005) [#4]
Uh, you can have recursive handles. You just have to clean um up manually.


gman(Posted 2005) [#5]
an example of storing a parent on the child and cleaning up after yourself:

Strict
Framework BRL.Blitz
Import BRL.LinkedList

Type widget
	Field name:String
	Field parent:widget=Null
	Field children:TList=Null
		
	Function createWidget:widget(name:String,parent:widget=Null)
		Local retval:widget=New widget
		retval.name=name
		retval.parent=parent
		Return retval
	EndFunction
	
	Method addchild:widget(name:String)
		' init the list
		If children=Null Then children=New TList
		Local retval:widget=widget.createWidget(name,Self)
		children.AddLast(retval)
		Return retval
	EndMethod
	
	Method clearChildren()
		If children<>Null
			Local child:widget
			' make sure we clear our childrens children
			For child=EachIn children
				child.clearChildren()
			Next
			' clear out the list
			children.Clear()
		EndIf
	EndMethod
	
	' delete will never fire unless all other references are gone first 
	Method Delete()
		DebugLog("destroying: "+name)
		parent=Null
	EndMethod
EndType

DebugLog("mem: "+MemAlloced())

' create the top level
Local testwidget:widget=widget.createWidget("top_level")

' create some first level children
testwidget.addchild(testwidget.name+": child1_1")
testwidget.addchild(testwidget.name+": child2_1")
testwidget.addchild(testwidget.name+": child3_1")

' create some second level children
Local child:widget
For child=EachIn testwidget.children
	child.addchild(child.name+": child1_2")
	child.addchild(child.name+": child2_2")
	child.addchild(child.name+": child3_2")
Next
child=Null

DebugLog("13 total nodes we should see cleaned up at the End")

DebugLog("mem: "+MemAlloced())

' this is the big key...  in order for something to be set to Null to work it
' must have no remaining references.  this is a problem if a child still has 
' a reference to the parent so you must get rid of the children first and those
' children must be sure to clean themselves up.
testwidget.clearchildren()
testwidget=Null

FlushMem

DebugLog("mem: "+MemAlloced())

should yield something like:

mem: 1902
13 total nodes we should see cleaned up at the End
mem: 3513
destroying: top_level: child3_1: child3_2
destroying: top_level: child3_1: child2_2
destroying: top_level: child3_1: child1_2
destroying: top_level: child2_1: child3_2
destroying: top_level: child2_1: child2_2
destroying: top_level: child2_1: child1_2
destroying: top_level: child1_1: child3_2
destroying: top_level: child1_1: child2_2
destroying: top_level: child1_1: child1_2
destroying: top_level: child3_1
destroying: top_level: child2_1
destroying: top_level: child1_1
destroying: top_level
mem: 1902

Process complete




The r0nin(Posted 2005) [#6]
That's pretty much the way I ended up doing it, except I didn't store the parent in a reference at all, just created a list for them. Also, instead of storing children (as I won't be using the code that way.. though I did build in a search routine to sort through the list for any child that has a parent's name... just in case, but slower), I only stored the parent of the object. Didn't have a list.clear() on the destruction routine, though, so that will be added.

My main curiousity was the difference in memory footprint across the different methods, as I may end up with lots of "widgets." But I guess if all that is being stored is a pointer to the object (whether is a object reference, a variable pointer, or an entry in a list), then it doesn't make much difference. Thanks for the input, folks!