Diddy: Concurrent list modification

Monkey Forums/Monkey Programming/Diddy: Concurrent list modification

Volker(Posted 2011) [#1]
Hi,

I'm tracing my objects with an Arraylist.
But when removing the objects, it fails with
"ListEnumerator.CheckConcurrency: Concurrent list modification"

Local t:Test=new Test
For Local test:Test=eachin t.cardlist
	test.Update()
Next


Class Test
		field cardlist:ArrayList<Test> = New ArrayList<Test>
		
		Method New()
			cardlist.AddLast(Self)
		End Method
		
		Method Update:Void()
			Self.Remove()
		End Method
		
		Method Remove:Void()
			Self.cardlist.Remove(Self)
		End Method
End Class



therevills(Posted 2011) [#2]
@Volker, yep thats correct you shouldnt be removing objects during a loop like that - also this should have been posted in the Diddy thread ;)


Samah(Posted 2011) [#3]
I'm not quite sure what you're trying to do there... should cardlist be Global instead of a Field? Surely you don't want an ArrayList for each instance of Test.

If you want to remove items in a loop, you should be using an enumerator.
Local enum:AbstractEnumerator<Test> = t.cardlist.Enumerator()
While enum.HasNext()
  Local test:Test = enum.NextObject()
  test.Update()
  If you want to remove it Then
    enum.Remove() ' notice we call Remove on enum rather than cardlist
  End
End

Explicitly removing items within a loop is dangerous depending on the current state of the list - you could accidentally skip items. Using the enumerator's built in Remove method will enforce the integrity of the list so that you're guaranteed to never skip an item.

Disclaimer: I haven't tried compiling this. :)

Read more about ArrayList here: http://code.google.com/p/diddy/wiki/ArrayList


dmaz(Posted 2011) [#4]
that's why I like linked lists better... but would iterating an array list backwards not have this problem?


Samah(Posted 2011) [#5]
@dmaz: but would iterating an array list backwards not have this problem?

Nope. When you use the Remove() method in the enumerator, it fixes the pointer to the array automatically so that NextObject() and PreviousObject() will correctly give you the item before or after the one you removed.
That's why you don't remove items manually. ;)


Volker(Posted 2011) [#6]
that's why I like linked lists better...

I used it before. But ValueatIndex() is lost in monkey, so I switched
to Arraylist.
I'm not quite sure what you're trying to do there... should cardlist be Global instead of a Field?

No. Test is in reality a card deck, which contains a list with all cards.
Read more about ArrayList here: http://code.google.com/p/diddy/wiki/ArrayList

Thanks guys, I must confess that I didn't even mentioned that
there is a wiki for diddy :-o.


Volker(Posted 2011) [#7]
I'm wondering, is it safe to remove objects from a monkey list
in a EachIn loop?

Local t:Test=new Test
For Local test:Test=eachin t.cardlist
	test.Update()
Next


Class Test
		Field cardlist:List<Test> = New List<Test>
		Field link:list.Node<Test>

		Method New()
			link=list.AddLast(Self)
		End Method
		
		Method Update:Void()
			Self.Remove()
		End Method
		
		Method Remove:Void()
			link.Remove()
		End Method
End Class



Samah(Posted 2011) [#8]
@Volker: I'm wondering, is it safe to remove objects from a monkey list
in a EachIn loop?

Probably, depending on how you do it. The problem shows itself more when you use a Stack, since it's indexed. There's an example on the Diddy wiki.


dmaz(Posted 2011) [#9]
is it safe to remove objects from a monkey list
yes