www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Killing the array you're iterating over

reply Nick Sabalausky <a a.a> writes:
How safe is it to do this?

MyClass[] array;
... // Put stuff into array
foreach(MyClass obj ; array)
{
    if(/+ some condition that may
          occur in one of the iterations +/)
    {
        array = null;  // Is this kosher?
    }

    ... // Do stuff, but nothing that touches array or obj
}

It works for me and simply has the effect of breaking out of the foreach 
loop at the end of the iteration. Is this behavior guaranteed? Or it is 
considered unsafe and likely to be either broken in certain 
circumstances or disallowed in the future?
Feb 25 2005
next sibling parent reply Nick Sabalausky <a a.a> writes:
I forgot to mention that in my particular case the line 'array=null;' is 
happening from within a member function of obj.  Specifically:

class MyClass
{
   void Foo()
   {
      Kill();
   }
}

MyClass[] array;

void Kill()
{
     array = null;
}

void Run()
{
   ... // Put stuff into array
   foreach(MyClass obj ; array)
   {
      if(/+ some condition that may
          occur in one of the iterations +/)
      {
          obj.Foo();
      }

      ... // Do stuff, but nothing that touches array or obj
   }
}

Nick Sabalausky wrote:
 How safe is it to do this?
 
 MyClass[] array;
 ... // Put stuff into array
 foreach(MyClass obj ; array)
 {
    if(/+ some condition that may
          occur in one of the iterations +/)
    {
        array = null;  // Is this kosher?
    }
 
    ... // Do stuff, but nothing that touches array or obj
 }
 
 It works for me and simply has the effect of breaking out of the foreach 
 loop at the end of the iteration. Is this behavior guaranteed? Or it is 
 considered unsafe and likely to be either broken in certain 
 circumstances or disallowed in the future?
Feb 25 2005
parent "Matthew" <admin stlsoft.dot.dot.dot.dot.org> writes:
I'll be very surprised if this is supported behaviour

"Nick Sabalausky" <a a.a> wrote in message 
news:cvobgr$1q8u$1 digitaldaemon.com...
I forgot to mention that in my particular case the line 'array=null;' 
is happening from within a member function of obj.  Specifically:

 class MyClass
 {
   void Foo()
   {
      Kill();
   }
 }

 MyClass[] array;

 void Kill()
 {
     array = null;
 }

 void Run()
 {
   ... // Put stuff into array
   foreach(MyClass obj ; array)
   {
      if(/+ some condition that may
          occur in one of the iterations +/)
      {
          obj.Foo();
      }

      ... // Do stuff, but nothing that touches array or obj
   }
 }

 Nick Sabalausky wrote:
 How safe is it to do this?

 MyClass[] array;
 ... // Put stuff into array
 foreach(MyClass obj ; array)
 {
    if(/+ some condition that may
          occur in one of the iterations +/)
    {
        array = null;  // Is this kosher?
    }

    ... // Do stuff, but nothing that touches array or obj
 }

 It works for me and simply has the effect of breaking out of the 
 foreach loop at the end of the iteration. Is this behavior 
 guaranteed? Or it is considered unsafe and likely to be either broken 
 in certain circumstances or disallowed in the future? 
Feb 26 2005
prev sibling parent reply "Walter" <newshound digitalmars.com> writes:
In general, it is a very bad idea to try to modify a collection in the
middle of a foreach.
Feb 27 2005
next sibling parent reply "Matthew" <admin.hat stlsoft.dot.org> writes:
But is this non-standard behaviour?

I think it should be defined as such for all cases, even if there are some
specific ones where it doesn't hold.

Specifically, I think one should always be allowed to modify a collection
(assuming it's modifiable) from within a 
foreach loop, but one the condition that the loop is terminated (by break /
return / goto / exception) without any 
further iterations.

"Walter" <newshound digitalmars.com> wrote in message
news:cvtcmq$qkc$1 digitaldaemon.com...
 In general, it is a very bad idea to try to modify a collection in the
 middle of a foreach.

 
Feb 28 2005
parent "Unknown W. Brackets" <unknown simplemachines.org> writes:
I agree; it is a common thing to do something such as this:

foreach (inout char c; str)
	if (c == 0)
	{
		// String contains invalid characters.
		str = null;
		break;
	}

Kinda dumb example, but the point is there, I think.

-[Unknown]


 But is this non-standard behaviour?
 
 I think it should be defined as such for all cases, even if there are some
specific ones where it doesn't hold.
 
 Specifically, I think one should always be allowed to modify a collection
(assuming it's modifiable) from within a 
 foreach loop, but one the condition that the loop is terminated (by break /
return / goto / exception) without any 
 further iterations.
Mar 15 2005
prev sibling next sibling parent "Carlos Santander B." <csantander619 gmail.com> writes:
Walter wrote:
 In general, it is a very bad idea to try to modify a collection in the
 middle of a foreach.
 
 
In my experience, foreach uses the original keys to iterate over: char [] [int] collection; void foo (int key) { ... might add elements to collection ... } void bar () { collection[4]="carlos"; foreach(int key, char [] value; collection) foo(key); } This will only iterate once. Since I needed to iterate even with the new elements, I ended up doing something like this: void bar () { int [] keys; void [int] already; while(true) { keys=collection.keys; foreach(int key, char [] value; collection) if ( ! (key in already) ) { foo(key); already[key]; } if (keys==collection.keys) break; } } I think the algorithm can be improved, but the other solution I tried (keeping another collection with just the items not iterated yet, and adding and removing elements every time), didn't work. _______________________ Carlos Santander Bernal
Mar 01 2005
prev sibling parent David Medlock <amedlock nospam.com> writes:
Walter wrote:

 In general, it is a very bad idea to try to modify a collection in the
 middle of a foreach.
 
 
Then why are these delegates using inout parameters? IMO there should be a delegate with an IN parameter or an void opApply( int delegate( in Type OldValue, out Type NewValue ) type method. I have already used temp variables in my opApply methods to avoid accidentally doing just this sort of mutation. -David
Mar 15 2005