Array element reference?

BlitzMax Forums/BlitzMax Programming/Array element reference?

Athos(Posted 2012) [#1]
I have a Type called TCard and another type called TCardList.
The TCardList manages an array which lists TCards types.
What I was planning was like:

[bbcode]
type TCardList
field Cards:TCard[5]
...

method AddCard(card:TCard var, pos:int) 'Passing card as reference
self.Cards[pos] = card
endmethod

...

method drawCards()
for local card:TCard = eachIn(self.Cards)
card.Draw()
next
endmethod
endType

global CARD_NAME:TCard = TCard.Create()

glboal APP_CARDS:TCardList = TCardList.Create()

APP_CARDS.AddCard(CARD_NAME, 0)
[/bbcode]

However, calling APP_CARDS.DrawCards() still draws the cards even when setting CARD_NAME to null...


Brucey(Posted 2012) [#2]
No, there must be something else you are doing, because I ran the same code with CARD_NAME as Null, and nothing is drawn. If CARD_NAME is a TCard then one card is drawn.

So, your example here is not what your real code is actually doing.

Runnable example :

SuperStrict

Framework BRL.StandardIO

Type TCard

Function Create:TCard()
	Return New TCard
End Function

Method draw()
	DebugLog "draw"
End Method

End Type

Type TCardList
	Field Cards:TCard[5]

Function Create:TCardList()
	Return New TCardList
End Function

	Method AddCard(card:TCard Var, pos:Int) 'Passing card as reference
		Self.Cards[pos] = card
	EndMethod

	

	Method drawCards()
		For Local card:TCard = EachIn(Self.Cards)
	DebugLog "looping"
			card.Draw()
		Next
	EndMethod
EndType

Global CARD_NAME:TCard' = TCard.Create()

Global APP_CARDS:TCardList = TCardList.Create()

APP_CARDS.AddCard(CARD_NAME, 0)

APP_CARDS.drawCards()


Last edited 2012


Athos(Posted 2012) [#3]
I modified the code a bit:

[bbcode]
SuperStrict

Graphics(640,480)

Type TCard
Function Create:TCard()
Return New TCard
End Function

Method draw()
DrawText("drawing card", 20, 20)
End Method
End Type

Type TCardList
Field Cards:TCard[5]

Function Create:TCardList()
Return New TCardList
End Function

Method AddCard(card:TCard Var, pos:Int) 'Passing card as reference
Self.Cards[pos] = card
EndMethod

Method drawCards()
For Local card:TCard = EachIn(Self.Cards)
'DebugLog "looping"
card.Draw()
Next
EndMethod
EndType

Global CARD_NAME:TCard = TCard.Create()

Global APP_CARDS:TCardList = TCardList.Create()

APP_CARDS.AddCard(CARD_NAME, 0)

While(Not AppTerminate() And Not KeyDown(KEY_ESCAPE))
Cls()

If(KeyDown(KEY_UP)) Then
CARD_NAME = Null
EndIf
APP_CARDS.drawCards()

Flip()
Wend
[/bbcode]

if you press the UP Arrow, the text will still be visible...


Brucey(Posted 2012) [#4]
Ah, I understand now :-)

Yes, your variable CARD_NAME holds a reference to a TCard object.
When you call AddCard, your array entry now also holds a reference to the same TCard object.

Next you set CARD_NAME to Null. All this does is clear the reference you are holding of that TCard object from the CARD_NAME variable. The object reference in the array is still there.

CARD_NAME is not like the physical entity of the TCard object. When you set CARD_NAME to null, you are just forgetting what was there, rather than deleting the TCard object.
If, however, you have no other references to this TCard in your program (i.e. not in the array, or not referenced by another variable, it will eventually be "cleaned up" by the garbage collector.

Here is another example…

Note that I've added a Delete() method to TCard. This will be called whenever the object is freed by the GC. You may need to run it for a WHILE for this to happen. Down arrow will clear the Array entry. You will need to do UP and DOWN to remove all references… then wait and while and you should see the Delete message pop up. (run in debug mode)

SuperStrict

Graphics(640,480)

Type TCard
	Function Create:TCard()
		Return New TCard
	End Function
	
	Method draw()
		DrawText("drawing card", 20, 20)
	End Method
	
	Method Delete()
		DebugLog "TCard says Goodbye"
	End Method
End Type

Type TCardList
	Field Cards:TCard[5]

Function Create:TCardList()
	Return New TCardList
End Function

	Method AddCard(card:TCard Var, pos:Int) 'Passing card as reference
		Self.Cards[pos] = card
	EndMethod

	Method drawCards()
		For Local card:TCard = EachIn(Self.Cards)
			'DebugLog "looping"
			card.Draw()
		Next
	EndMethod
EndType

Global CARD_NAME:TCard = TCard.Create()

Global APP_CARDS:TCardList = TCardList.Create()

' Let's not add it and see what happens eventually...
APP_CARDS.AddCard(CARD_NAME, 0)

While(Not AppTerminate() And Not KeyDown(KEY_ESCAPE))
	Cls()
	
	If(KeyDown(KEY_UP)) Then
		CARD_NAME = Null
		DebugLog "Nulling CARD_NAME"
	EndIf
	
	If KeyDown(KEY_DOWN) Then
		APP_CARDS.Cards[0] = Null
		DebugLog "Nulling Array entry"
	End If
	APP_CARDS.drawCards()
	
	DrawText "La la la", 10, 400
	Flip()
Wend



Derron(Posted 2012) [#5]
yes...

step by step:

Global CARD_NAME:TCard = TCard.Create()
-> store the new created card in CARD_NAME

APP_CARDS.AddCard(CARD_NAME, 0)
-> store the CARD_NAME-card within the Cards-Array

(now CARD_NAME -AND- the Cards-Array held a reference to the object)

If(KeyDown(KEY_UP)) Then CARD_NAME = Null
-> if KEY_UP is pressed, the reference CARD_NAME is nulled
-> Cards-Array is still helding 1 reference


There is no need for you to reference "CARD_NAME"
just:
APP_CARDS.AddCard(TCard.Create(), 0)

Will do it.
To remove one card, do the opposite of adding one... set the Array-Slot to null.

bye
Ron

Edit: Brucey was some seconds faster :D

Last edited 2012


Brucey(Posted 2012) [#6]
There is no need for you to reference "CARD_NAME"

True in this case, but it will all come to him once he grasps the "reference" concept I think ;-)


Athos(Posted 2012) [#7]
I get it now...

I thank you both for the help :D


Htbaa(Posted 2012) [#8]
Sidenote, why does AddCard requires a reference to a TCard object? Objects are always passed by reference so there's no need for using Var.


Brucey(Posted 2012) [#9]
I didn't even notice that was there. Perhaps it's from another language that does parameter passing like that ?


Derron(Posted 2012) [#10]
http://en.wikibooks.org/wiki/BlitzMax/Modules/BASIC/BlitzMax_runtime#Var

I use "var" in certain sources too (not quiete sure if only for ints...)

As it explizit states: "the param used here is a reference the function/method may and will alter"
I think that is ok to do so - except in this case there it is not needed.


Like Brucey mentioned: if coming from other languages (or using more than 1-2) you are used to state whether params are copies of an object or reference links... (like php etc.).


bye
Ron


Bobysait(Posted 2012) [#11]
If you use Var on a type, you can set it to Null in the function, it should set the "original" to Null too (If I 'm not wrong)
Else, it's generally to affect variables int/float/etc types as we know it.

By the way, we can't use it as c++ pointers (like MyClass &obj / MyClass * Obj, one create a variable wich old the values of obj, so you can modify the obj, but not "re-reference it", the other send the real pointer, so we can set obj to null and affect it in the main program)
In blitzmax, it is relevant if we affect the pointer in the function, but if we store it in and array, the pointer can't only be registered as copy
So, modifying the linking of the array won't affect the original.

(this is probably due to the garbage Collector of Blitzmax which probably does not support advanced pointers, but here, I'm conjecturing)


Whatever, it's of course not relevant in the exemple above




ps : Blitz3D do a better job on type (for this purpose)
> if you delete a type, it is setted to Null whatever you manually do it or not anywhere you assigned a variable to it, then all assignment to the instance is also set to Null




Bobysait(Posted 2012) [#12]
small sample to show how to use Var on types (and prove it works)

Type T
	
	Function DoNothing(a:T)
		a = Null
	End Function
	
	Function SetToNull(a:T var)
		a = Null
	End Function
	
End Type

Local a:T = New T
t.DoNothing(a)
Print (a <> Null)

t.SetToNull(a)
Print (a <> Null)

WaitKey
End