Working with list in Monkey

Monkey Forums/Monkey Programming/Working with list in Monkey

FBEpyon(Posted 2011) [#1]
Hello All,

I have looked thru the whole set of list examples but I myself still don't understand why list are so much different from Blitzmax..!

Does anyone have a better example of how to make list easier to work with in Monkey..?

Fbepyon


muddy_shoes(Posted 2011) [#2]
Could you be more specific? What is it that you think should be easier?


AdamRedwoods(Posted 2011) [#3]
We probably need a tutorial.

But until then:

Class CBullet
  Global bulletlist:List<CBullet> = New List<CBullet>
  Field x:Int, y:Int


  Global b:CBullet '' used for loops to deter GC

  Method New()
    bulletlist.AddLast(self)
  End

  Function Update()
    For b = Eachin bulletlist
       ''do something
    Next
  End
End


Or even:
Class CBulletList Extends List<CBullet>
  ''add your custom Sort() here, if desired
End

''then use
Class CBullet
  Global bulletlist:CBulletlist = New CBulletlist
  ''...etc...
End



Jesse(Posted 2011) [#4]
double post


Jesse(Posted 2011) [#5]
I don't know if this will help you but here is my 2 cents description:

Class myClass
....
End Class

Local myList:List<myClass> ' this means you can only insert objects of Class 'myClass'.

this works:
Local myObject := New myClass
myList.AddLast(myObject)


this fails To compile:
Local myObject := New otherClass
myList.AddLast(myObject) ' this fails because it only supposed to accept "myClass" objects.

you can only insert one type of objects as defined during the list Object creation. it will give an error otherwise.

you can however store different class objects in the list If they have been extended from a common base Class such as in
polymorphy.
example:
Class base
....
End

Class thisClass Extends base
...
End

Class thatClass Extends base
...
End

Local myList:List<base>
Local thisObject:base = New thisClass
myList.AddLast(thisObject)
Local thatObject:base = New thatClass
myList.AddLast(thatObject)


To extract from the List
For Local myObject:Tbase = Eachin myList
	If thisClass(myObject)
		Local this:thisClass = thisClass(myObject)
		'process 'this' object
	Elseif thatClass(myObject)
		Local that:thatClass = thatClass(myObject)
		'process 'that' object
	Endif
Next 


hope this didn't confuse you even more.


Samah(Posted 2011) [#6]
@AdamRedwoods Global b:CBullet '' used for loops to deter GC

How does that deter GC? The object creation is in the ObjectEnumerator call that EachIn automatically does.

From the official Monkey List class:
Method ObjectEnumerator:Enumerator<T>()
	Return New Enumerator<T>( Self )
End



AdamRedwoods(Posted 2011) [#7]

How does that deter GC? The object creation is in the ObjectEnumerator call that EachIn automatically does.


Mostly effects Java.

When looking at the resulting code from the Java output, ObjectEnumerator is called once before the loop, so it doesn't effect the GC much. BUT-- If I use:
For Local b:CBullet = Eachin bulletlist

The loop will create a CBullet object each time.
THEREFORE-- if I use the global variable like the above, the loop uses a static variable outside the loop, thus decreasing the number of times we create a new object (deterring GC).


Samah(Posted 2011) [#8]
If this EachIn is being called even once every OnUpdate or OnRender, that's a hell of a lot of objects being created. Declaring a variable is not the same as instantiating an object.
Can you post the generated Java code?


therevills(Posted 2011) [#9]
This is what your class turns into:
class bb__CBullet extends Object{
	static bb_list_List bb_bulletlist;
	public bb__CBullet bb_CBullet_new(){
		bb_bulletlist.bbm_AddLast(this);
		return this;
	}
	static bb__CBullet bb_b;
	static public void bb_CBullet_Update(){
		bb_list_Enumerator bbt_=bb_bulletlist.bbm_ObjectEnumerator();
		while(bbt_.bbm_HasNext()){
			bb_b=((bb__CBullet)(bbt_.bbm_NextObject()));
		}
	}
}


And if you do the For Local bb:CBullet = Eachin bulletlist it turns into this:
class bb__CBullet extends Object{
	static bb_list_List bb_bulletlist;
	public bb__CBullet bb_CBullet_new(){
		bb_bulletlist.bbm_AddLast(this);
		return this;
	}
	static public void bb_CBullet_Update(){
		bb_list_Enumerator bbt_=bb_bulletlist.bbm_ObjectEnumerator();
		while(bbt_.bbm_HasNext()){
			bb__CBullet bbt_bb=((bb__CBullet)(bbt_.bbm_NextObject()));
		}
	}
}


Spot the difference


Samah(Posted 2011) [#10]
From therevills' code:
bb__CBullet bbt_bb=((bb__CBullet)(bbt_.bbm_NextObject()));
This declares a local variable. It doesn't create an object.

bb_list_Enumerator bbt_=bb_bulletlist.bbm_ObjectEnumerator();
This creates an object within bbm_ObjectEnumerator();
Even one object created every loop is too many.

Kudos for trying to optimise GC calls though. :)


AdamRedwoods(Posted 2011) [#11]
Ah, I see now. The only difference is the static definition. No GC.


dmaz(Posted 2011) [#12]
If this EachIn is being called even once every OnUpdate or OnRender, that's a hell of a lot of objects being created.
just to clarify... it's not EachIn that creates the object, it's the class's ObjectEnumerator method that does. so we can easily use EachIn with pooled Enumerators. And in regard to the static/global outside the loop... the local declaration -inside- the loop will be faster even in Java as access to local variables and parameters in methods are much faster than access to static or instance
fields. this is and has been a standard recommended performance enhancement. I know it seems counter intuitive but it comes down to the extra overhead a global requires and the fact that the local will most likely stay on register (and if not then the higher on the stack the better chance to stay in cache). *I have actually tested this although not on every device.

edit: I should point out that if you really want to trimm everything then don't use EachIn even with pooled Enums... as there are the HasNext() function calls and also no way to unroll the loop.


AdamRedwoods(Posted 2011) [#13]
I thought NOT using globals would be faster as well, but for Java, I ended up with 10-20ms faster here.

http://www.monkeycoder.co.nz/Community/post.php?topic=1226&post=11179

Overall, the differences are so minor that it doesn't matter.


Samah(Posted 2011) [#14]
@dmaz just to clarify... it's not EachIn that creates the object, it's the class's ObjectEnumerator method that does

@Samah This creates an object within bbm_ObjectEnumerator();

My point is that apart from arrays, all the enumerable system classes in Monkey create an object. I'm thinking of adding pooling to ArrayList, because at the moment it's still better to use Size and Get if you're targeting Android.

Having said that, the Enumerator in ArrayList is a little more advanced than the official List one. It protects against concurrent modification, and if you manually retrieve it with .Enumerator(), you can traverse back and forth (indexed) and remove items dynamically. You can manually reset the enumerator to its default state by calling .Reset()


FBEpyon(Posted 2011) [#15]
@ AdamRedwoods

That makes things alot better, and I was being stupid as it was because I was forgetting the SELF part of the classes (like blitzmax)..

The reason I was wanting more information on the list is because I use it for all my map objects in my game..

Thanks All


zardon(Posted 2013) [#16]
How do you find out the size of a list?


Midimaster(Posted 2013) [#17]
Global propertyCards:List<fsProperty> = New List<fsProperty>
Print propertyCards.Count()