Profundal insight #453: arrays or lists in persistent objects failto get cleared

  • Thread starter Thread starter RayLopez99
  • Start date Start date
R

RayLopez99

Just an observation that I'm sure you experienced coders may have
noticed: if you have a list or array, and attempt to zero or .clear
it in one portion of your code, if that list or array appears in
another portion of your code it can still be "persistent" and non-
zero.

The solution: you have to go to that other portion of your code and
'zero it' or 'clear it' there, sometimes by dealing with the
persistent object itself and zeroing or clearing any data that gets
fed into the list or array you wish to clear.

If none of this makes sense, it's because you haven't coded enough.
Sorry I can't spoon feed you. Jon that means you, whereever you are.

I guess one solution, other than what I said above, is to manually
garbage collect the other portion of code that is causing your list or
array to be non-zero, but that has problems I think (I never touch the
garbage collection but rely on the automatic pilot).

So, my original solution of just zeroing or clearing any data feeding
into the array or list should work.

No big deal, but when OnPainting I was seeing stuff in my array/list
that I thought I had cleared, and I discovered it was because of
another persistent object that was hanging around and had a reference
to the array/list that was zeroed/cleared elsewhere in the code.

RL
 
RayLopez99 said:
Just an observation that I'm sure you experienced coders may have
noticed: if you have a list or array, and attempt to zero or .clear
it in one portion of your code, if that list or array appears in
another portion of your code it can still be "persistent" and non-
zero.

The solution: you have to go to that other portion of your code and
'zero it' or 'clear it' there, sometimes by dealing with the
persistent object itself and zeroing or clearing any data that gets
fed into the list or array you wish to clear.

If none of this makes sense, it's because you haven't coded enough.
Sorry I can't spoon feed you. Jon that means you, whereever you are.

I guess one solution, other than what I said above, is to manually
garbage collect the other portion of code that is causing your list or
array to be non-zero, but that has problems I think (I never touch the
garbage collection but rely on the automatic pilot).

So, my original solution of just zeroing or clearing any data feeding
into the array or list should work.

No big deal, but when OnPainting I was seeing stuff in my array/list
that I thought I had cleared, and I discovered it was because of
another persistent object that was hanging around and had a reference
to the array/list that was zeroed/cleared elsewhere in the code.

RL


I needed a brain teaser tonight, so I tried to figure out what you were
trying to describe. This contrived case may illustrate what you witnessed,
but, of course it is obvious why it does so...

using System;
using System.Collections.Generic;
using System.Linq;

namespace UnemptiedList
{
class Program
{
static void Abuser(List<string> testlist)
{
testlist.Clear();
Console.Out.WriteLine(
string.Format("In Abuser, testlist has {0} elements after clear.",
testlist.Count));
}

static void Main(string[] args)
{
string [] colors = new string [] { "red", "white", "blue" };

Console.Out.WriteLine(
string.Format("In main, before routine, colors has {0} elements.",
colors.Length));

Abuser(colors.ToList<string>());

Console.Out.WriteLine(
string.Format("In main, after routine, colors has {0} elements.",
colors.Length));

Console.In.ReadLine();
}
}
}
 
RayLopez99 said:
Just an observation that I'm sure you experienced coders may have
noticed: if you have a list or array, and attempt to zero or .clear
it in one portion of your code, if that list or array appears in
another portion of your code it can still be "persistent" and non-
zero.

The solution: you have to go to that other portion of your code and
'zero it' or 'clear it' there, sometimes by dealing with the
persistent object itself and zeroing or clearing any data that gets
fed into the list or array you wish to clear.

If none of this makes sense, it's because you haven't coded enough.
Sorry I can't spoon feed you. Jon that means you, whereever you are.

I guess one solution, other than what I said above, is to manually
garbage collect the other portion of code that is causing your list or
array to be non-zero, but that has problems I think (I never touch the
garbage collection but rely on the automatic pilot).

So, my original solution of just zeroing or clearing any data feeding
into the array or list should work.

No big deal, but when OnPainting I was seeing stuff in my array/list
that I thought I had cleared, and I discovered it was because of
another persistent object that was hanging around and had a reference
to the array/list that was zeroed/cleared elsewhere in the code.

RL

Ray, I think you have a fundamental misconception going on here.

If you have a COPY of an array or list somewhere else, clearing one of the
copies doesn't clear the others. But if you pass around a REFERENCE to an
array or a list, there's only and exactly one copy of it. Clearing it in one
place, through that reference, clears it for everyone else that holds a
reference to the same collection and refers to it through that reference.

I can't help you with your code, of course, but I suggest that you look a
little deeper into what you're doing and see if you're in fact replicating
copies of the array or list contents, instead of merely passing around
references to a single object.

Tom Dacon
Dacon Software Consulting
 
Ray, I think you have a fundamental misconception going on here.

If you have a COPY of an array or list somewhere else, clearing one of the
copies doesn't clear the others. But if you pass around a REFERENCE to an
array or a list, there's only and exactly one copy of it. Clearing it in one
place, through that reference, clears it for everyone else that holds a
reference to the same collection and refers to it through that reference.

I can't help you with your code, of course, but I suggest that you look a
little deeper into what you're doing and see if you're in fact replicating
copies of the array or list contents, instead of merely passing around
references to a single object.

Tom Dacon
Dacon Software Consulting

Thanks, that's great and I agree, but it's not obvious to me where I'm
making a copy of the array I'm trying to clear. In fact, I can't find
that a copy exists. Now it's true that I use a list, along
with .ToArray() to make a copy of an array (from the list), but this
should not (I would argue) create a copy of the list. So, when you
clear the list, it should clear "globally". But, perhaps behind the
scenes when you do a MyList.ToArray() you are in fact making a hidden
copy somewhere, that is persistent, and this hidden copy is why your
list does not empty.

Just guessing.

In any event thanks for that input. It's not a big deal, but it's of
interest. When you code is over 100 pages (as is my simple app, in
Windows Forms) it's hard to keep track of when you are passing a
reference and when passing a copy of a reference--better to simply
debug it and see what works. If it ain't broke...

RL
 
FTM--thank you. I intend to run this and study it; if I have comments
I'll post. But just in case, can you tell me why you think this works
the way it does? Thanks in advance and happy Turkey day (I'm outside
the US and it' s not a holiday here).

RL
 
RayLopez99 said:
FTM--thank you. I intend to run this and study it; if I have comments
I'll post. But just in case, can you tell me why you think this works
the way it does? Thanks in advance and happy Turkey day (I'm outside
the US and it' s not a holiday here).

RL


Thanks, I'm trying to stay out of the way of the cooks...

Basically my code is similar to Tom's thought. The .ToList<string>() in the
call does not treat the array as a list, but rather creates a list from the
array. Therefore, the array is not being cleared, but rather the list which
is only a copy of the array gets cleared.

If you created a temp list first, then compared it after the call, it would
be cleared in the main routine.

Mike
 
On Nov 27, 5:25 am, "Family Tree Mike"

FTM--thanks for your input, below is what I figured out using your
code and adding to it... RL

// 11-27-08
I was able to replicate the anomaly I described in the original post.
I replicated it in console mode, but it’s otherwise the same as what
appeared in my Windows Forms program.

The key is this, as Tom Dacon alluded to in his post: a list ‘copied’
to another list merely keeps references tracked, while a list ‘copied’
to an array makes copies of the reference to the list (sorry if my
lingo is wrong) and thus erasing the list will not erase the array
copies.

This can be seen clearly in the lines below at “//CLEARLY1” below
(keyword search this). Note the list in class SecondClass has been
zeroed, but the array has not been, despite the fact that the original
list has been emptied. Thus the string “red, white, blue” still
appears in the array but not the list of class SecondClass.

This anomaly occurs in programs when painting rectangles, since the
rectangle fill method in Windows Forms only accepts an array of
rectangles not a list of rectangles (to my knowledge). So in my
Windows Forms program I was using AListOfRectanglesToPaint.ToArray()
to copy to an array, and thus this anomaly was occurring even after I
had zeroed or erased the list AListOfRectanglesToPaint.

RL


// OUTPUT (keyword search “CLEARLY1”)

In main, before routine, colors has 3 elements.
In Abuser, testlist has 0 elements after clear.
In main, after routine, colors has 3 elements.
In main, before routine, colors has 3 elements.
In Abuser, testlist has 0 elements after clear.
In main, after routine, colors has 3 elements.

Now see this difference 2

In Abuser2, testlist has 0 elements after clear.
In main 2, after routine, myProgram.testlist has: 0 elements
now watch effect of second class that stores testlist

testlistTWO, arrayTWO count, lengths are: 3, 3
print SecondClass list...
red
white
blue
print SecondClass array...
red
white
blue
In Abuser2, testlist has 0 elements after clear.
In main 3, after routine, myProgram.testlist has: 0 elements
print SecondClass list... //CLEARLY1
print SecondClass array...
red
white
blue

Press any key to continue . . .

////////////////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConA
{
class Program
{
List<string> testlist;

static void Abuser(List<string> testlist)
{
testlist.Clear();

Console.Out.WriteLine(string.Format("In Abuser, testlist
has {0} elements after clear.", testlist.Count));
}

void Abuser2(List<string> testlist)
{
testlist.Clear();
Console.Out.WriteLine(string.Format("In Abuser2, testlist
has {0} elements after clear.", testlist.Count));
}


static void myListClear(List<string> testlist)
{
testlist.Clear();
}



static void Main(string[] args)
{

Program myProgram = new Program();
string[] colors = new string[] { "red", "white", "blue" };
myProgram.testlist = colors.ToList<string>();
Console.Out.WriteLine(string.Format("In main, before
routine, colors has {0} elements.",colors.Length));
Abuser(colors.ToList<string>());
Console.Out.WriteLine( string.Format("In main, after
routine, colors has {0} elements.", colors.Length));

Console.WriteLine("\n Now see this difference 2 \n");
myProgram.Abuser2(myProgram.testlist);
Console.WriteLine("In main 2, after routine,
myProgram.testlist has: {0} elements", myProgram.testlist.Count);

Console.WriteLine("now watch effect of second class that
stores testlist \n");
myProgram.testlist = colors.ToList<string>();
SecondClass my2ndClass = new SecondClass
(myProgram.testlist);
my2ndClass.PrintOutArrayAndList();
myProgram.Abuser2(myProgram.testlist);
Console.WriteLine("In main 3, after routine,
myProgram.testlist has: {0} elements", myProgram.testlist.Count);
my2ndClass.PrintOutArrayAndList(); //CLEARLY1

Console.In.ReadLine();


}



}
}

/////////////////////////////////////

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ConA
{
class SecondClass
{
public List<string> testlistTWO;
public string[] testArrayTWO;

public SecondClass(List<string> aList)
{
testlistTWO = aList; //CLEARLY1
testArrayTWO = aList.ToArray(); //CLEARLY1
Console.WriteLine("testlistTWO, arrayTWO count, lengths
are: {0}, {1}", testlistTWO.Count, testArrayTWO.Length);

}
public void PrintOutArrayAndList ()
{
Console.WriteLine("print SecondClass list..."); //
CLEARLY1
foreach (string s in testlistTWO)
{ Console.WriteLine(s); }

Console.WriteLine("print SecondClass array..."); //
CLEARLY1
foreach (string s2 in testArrayTWO)
{ Console.WriteLine(s2); }
}


}
}

/////////////////////////////////////
 
Just an observation that I'm sure you experienced coders may have
noticed:  if you have a list or array, and attempt to zero or .clear
it in one portion of your code, if that list or array appears in
another portion of your code it can still be "persistent" and non-
zero.

It depends on exactly what you mean by "that list or array". If you've
got a separate reference to the same collection object, then after
clearing it in one place it *will* be clear when you reference it in
the other place.

(There are some subtle threading effects which could affect this, but
I very much doubt that they're relevant to what you're seeing.)
The solution:  you have to go to that other portion of your code and
'zero it' or 'clear it' there, sometimes by dealing with the
persistent object itself and zeroing or clearing any data that gets
fed into the list or array you wish to clear.

Not if the two pieces of code are *actually* referring to the same
collection (rather than to, say, a copy of it).
If none of this makes sense, it's because you haven't coded enough.
Sorry I can't spoon feed you.  Jon that means you, whereever you are.

Well, I've coded plenty and I can only guess what you mean - it's
pretty confused. Without an example, we are *only* left with guesses,
because your terminology isn't being precise enough. There's a big
difference between writing clearly and spoonfeeding.

If you provide an example, we can explain it.

Jon
 
The key is this, as Tom Dacon alluded to in his post:  a list ‘copied’
to another list merely keeps references tracked, while a list ‘copied’
to an array makes copies of the reference to the list (sorry if my
lingo is wrong) and thus erasing the list will not erase the array
copies.

No, lists and arrays behave the same way - if you copy the contents of
one list into another, they are independent collections. Clearing one
will not clear the other. The same is true for arrays.

Note that there is a big difference between creating a copy of a list
and copying the reference to a list into another variable.

As ever, the example you gave is far too long to easily deconstruct
(at least when working on a 9" screen). If you can give a *short* but
complete example of what surprises you, it will be easy to explain
what's going on.

Jon
 
No, lists and arrays behave the same way - if you copy the contents of
one list into another, they are independent collections. Clearing one
will not clear the other. The same is true for arrays.

Note that there is a big difference between creating a copy of a list
and copying the reference to a list into another variable.

As ever, the example you gave is far too long to easily deconstruct
(at least when working on a 9" screen). If you can give a *short* but
complete example of what surprises you, it will be easy to explain
what's going on.

Jon

Hey Jon, good to see you back. That consulting gig lasted all of one
week I see, and now you're unemployed again.

You need to get a bigger screen. There's only so much you can see on
a Blackberry... And even without a PC an experienced programmer
(cough, cough) should be able to figure out how the simple program I
cut and paste works. I keyword marked the relevant passages--it was
as Tom Dacon said.

But seriously, welcome back Kotter.

RL
 
You need to get a bigger screen.  There's only so much you can see on
a Blackberry...  And even without a PC an experienced programmer
(cough, cough) should be able to figure out how the simple program I
cut and paste works.

I can figure out how it works, but it takes longer than it would have
done if you'd written a *short* but complete program to start with.
And it *still* has nothing to do with the difference between arrays
and lists. It has everything to do with the difference between making
a copy of a collection and making a copy of a *reference*.

If you change this line:

testlistTWO = aList; //CLEARLY1

to

testlistTWO = aList.ToList(); //CLEARLY1

then you'll be making a copy (just as ToArray does) and clearing aList
won't have any effect. So where is this significant difference you
were claiming? (There certainly *are* significant differences between
arrays and lists, but you haven't mentioned any of them.)

Jon
 
If you change this line:

testlistTWO = aList;  //CLEARLY1

to

testlistTWO = aList.ToList();  //CLEARLY1

then you'll be making a copy (just as ToArray does) and clearing aList
won't have any effect. So where is this significant difference you
were claiming? (There certainly *are* significant differences between
arrays and lists, but you haven't mentioned any of them.)

Jon

Hot dang, I'll try that and make a note of it.

Feel free to post or otherwise mention an example of that threading
problem you mentioned earlier that also causes this anomaly. Note to
self: a good book on multithreaded programs and how to write the same
seems to be lacking.

Thanks,

RL
 
"Jon Skeet [C# MVP]" <[email protected]> a écrit dans le message de groupe de
discussion :
(e-mail address removed)...
You need to get a bigger screen. There's only so much you can see on
a Blackberry... And even without a PC an experienced programmer
(cough, cough) should be able to figure out how the simple program I
cut and paste works.

I can figure out how it works, but it takes longer than it would have
done if you'd written a *short* but complete program to start with.
And it *still* has nothing to do with the difference between arrays
and lists. It has everything to do with the difference between making
a copy of a collection and making a copy of a *reference*. [...]
then you'll be making a copy (just as ToArray does)

Maybe the point really relevant to the initial poster is that converting
from one type to another often implies that embedded data will be copied (so
that contracts of each type can be maintained).

I think that the point to stress is that ToArray *does* a copy (as you
said).
 
Christophe Lephay said:
I can figure out how it works, but it takes longer than it would have
done if you'd written a *short* but complete program to start with.
And it *still* has nothing to do with the difference between arrays
and lists. It has everything to do with the difference between making
a copy of a collection and making a copy of a *reference*. [...]
then you'll be making a copy (just as ToArray does)

Maybe the point really relevant to the initial poster is that converting
from one type to another often implies that embedded data will be copied (so
that contracts of each type can be maintained).

I think that the point to stress is that ToArray *does* a copy (as you
said).

Indeed - as does ToList().

What *doesn't* copy the contents of a collection is simply assigning
the value of one variable to another:

List<string> secondList = firstList; // Both refer to the same list now
 
Back
Top