How do you make an array persistent?

  • Thread starter Thread starter raylopez99
  • Start date Start date
R

raylopez99

I have an array that I wish to preserve as "read only". The array
holds references to variables myObjects instantiated by new that
change all the time.

The variables are part of a class that I used ICloneable on, namely
"Clone();" (deep and/or shallow copies worked the same for this
particular class).

Using ICloneable, I am able to successfully make a copy of the
variables like so:

myObjectsArray[j] = (MyObjects)X.Clone(); where X is foreach
(myObject X in myObjectsArray)

Everything is working fine except for one thing: I can only preserve
a copy of the array using IClone one time. After that, the array is
no good. But actually I'm quite happy even that this occurs, since my
purpose was to rollback the state of my program using myObjects just
once. So the program works. But I want to know for future reference
how to make the myObjectsArray persistent.

Do I make it 'readonly'? But this only seems to work for ints,
doubles, etc?

Do I use the template (found in a lot of books) of "memento design
pattern" (used in rollbacks)? It looks complicated, a bit of overkill
for this simple problem.

There is a chance that I'm messing up how I pass the 'read only"
array, myObjectsArray[].

Here is how I use it (perhaps I change it involuntarily?)


public void Rollback (myObjectsArray[] OASnapshot)
{

if (myObjectsList.Count != 0) { myObjectsList.Clear(); } //
clear list

myObjectsList = new
List<myObjects>(OASnapshot.Length); /

myObjectsList.AddRange(OASnapshot); //**
}

//** this works to repopulate the List with the 'old' values in
OASnapshot, which is exactly what I want. However, the second time I
call this method "Rollback", later on when the objects have changed
values, OASnapshot does not seem to have any of the 'old' information
of the objects, as I want, but in fact, OASnapshot seems to have
exactly the same information found in myObjectsList. Somehow
OASnapshot is not holding the old values (the second time around).


I tried using 'ref' for OASnapshot but same thing. I think what is
happening is that because of garbage collection, somehow OASnapshot is
not persistent.

Anyway, does this ring a bell with anybody?

RL
 
You can make an array *variable* readonly, but the contents of the
array can be changed, even for int etc, simply via the indexer:

readonlyArray[3] = 12; // perfectly legal

You can use readonly lists in some circumstances, but this only stos
you changing the contents of the list; if the items are themselves
mutable (like regular objects tend to be) you can still mutate the sub-
object:

readonlyList[3].Foo = "bar"; // perfectly legal

So to do what you want, you need a readonly list *and* immutable
objects. No small order.

If you want a true "deep" memento where you can rebuild the entire
state without having to worry about complex changes in between, then
perhaps serialize to binary and store the byte[]; or maybe a string
but it will take more space. The string would be immutable, but with a
byte[] approach - simply don't change the contents ;-p

Marc
 
readonly object read only array ICloneable cloning object clone deep
copying shallow copying

So to do what you want, you need a readonly list *and* immutable
objects. No small order.

If you want a true "deep" memento where you can rebuild the entire
state without having to worry about complex changes in between, then
perhaps serialize to binary and store the byte[]; or maybe a string
but it will take more space. The string would be immutable, but with a
byte[] approach - simply don't change the contents ;-p

Marc Gravell--you're absolutely right, it's no small order, in
general. But, with a good night's sleep, I figured out a simple
workaround for my particular problem.

First, I constructed a separate helper class apart from the two
classes that were interacting, because I surmised that garbage
collection and/or workings behind the scene (the gurus of this
newsgroup could clarify better--I don't care) were changing the
contents of the list/arrays being created, every time save the first
time they were used, as I indicated in the OP.

Then, I created a Queue of such arrays in the separate helper class.
I then copied the array I wanted to preserve as "read only" into the
Queue multiple times (pushed it in) --say 100 times--which is a
sufficient number of 'rollbacks' if you will. Then, whenever I want
to read this "read only" array, I pop from the Queue. Problem solved.
Of course this will only work for "100 rollbacks" but you can simply
push more than 100 rollbacks into the Queue--you have to plan ahead of
time how many copies to push of the array you want preserved. It's
thus not a true 'read only' array, which can be read an infinite
number of times, but, for my purposes, it's good enough, since I can
set the rollback number as high as I want (subject to memory limits).
BTW the 'separate helper class' was not ICloneable (no need).

For anybody reading this thread--you still need to create ICloneable
for the object you want preserved, otherwise no state information is
frozen in time.

In particular, on this last point, a very important step is the
following: myObjectsArray[j] = (MyObjects)X.Clone(); where X is
foreach
(myObject X in myObjectsArray). What this pseudocode says is that for
every myObject X, the class myObject must be derived from ICloneable
and you must do either a deep or shallow copy (for my simple class a
shallow copy was sufficient) of MyObject into the myObjectsArray array
storing these MyObjects (this array to be passed to the separate
helper class, as I said above). On how to set up any class for deep
or shallow copying using ICloneable, see for example C# Cookbook, 2nd
edition, by O'Reilly, 3.26 "Building Cloneable Classes". It's not
hard, if you follow the recipe given in the Cookbook.

That fact, and the fact the helper class is separate from the two
classes that interact, was what solved this problem for me.

RL
 
Well, I spoke too soon.

Turns out I didn't really have a solution after all (I assume so after
a quick check but it was premature).

Despite my best efforts tweaking the program, using "Clone" instead of
copy everywhere for arrays, using 'new' for arrays and doing a array
element by element clone copy from one array to another (even three
arrays in a row, A->B->C, in a vain attempt to get away from the
dreaded original reference), using Deep Copying for the Clone
function, and making every class I could think of as inheriting
ICloneable, I cannot get the array to be read more than once before it
changes state. That is, undo works just once.

I think the solution is like Marc Gravell said, and that involves
setting up a memento design pattern as I indicated in the OP.

Another solution, which is not really a solution, is to break down the
state you want to reconstruct into primitive data types (int, float,
etc), save this data, and 'reconstruct the state' using this data,
using functions in each of the interacting classes and as the program
dictates. But that 'solution' is hard work, just as hard or harder
than setting up a memento design pattern. In fact it nearly defeats
the purpose of 'undo' if you have to resort to such a drastic solution
(because after the undo you have to reconstruct the present state
too).

I consider this a defect of C#. You should be able to do this more
easily--there should be a library function that will preserve, in
immutable form, all references to mutable objects allowing you to
reconstruct the mutable objects as they were. Of course the memento
design pattern is such a solution, but what I'm saying is that this
memento design pattern should be built into C# as a language feature.
I heard the C# designers deliberately, unlike in C++, did not
introduce the 'const' (constant) keyword for reference objects/
variables, but this deliberate design choice is a defect IMO. A
'const' keyword would go a long way towards solving this problem,
though I'm sure some guru will point out that the IL engine working in
the background will be confused by a 'const' reference, since stuff
changes behind the scenes and nothing is constant save perhaps the
unboxed primitive data types (int, double, bool) on the stack.

RL
 
Well, I spoke too soon.

Turns out I didn't really have a solution after all (I assume so after
a quick check but it was premature).

I found a 'solution' and it is rather inelegant--you just keep making
multiple copies of the state you want, then Push it into a Stack.
Then you Pop it from the stack when you want to "undo".

It's basically the same as what I said in my second post, but you
don't use arrays or lists, which were causing problems because of the
"Predicate" (this was a complicated class, and you needed to set up
the Predicate/Action <T> because the default apparently was not
working--too much bother, just use Stack)

Still, it would be nice to have something 'built into' the C# language
for readonly instead of depending on a inelegant programmers solution.

RL
 
I consider this a defect of C#.
....
Still, it would be nice to have something 'built into' the C# language

Why? How many other similar languages offer this? C++? java? nope.
Arguably some *libraries* might offer this, but you need to think of
the language and the library as separate entities. Another approach is
to work with immutable objects; immutable objects tend to be more
common in java than C# - but by definition with an immutable object
you don't need to worry about changes... your downstream code might
have a slightly different *copy* of the data, but your upstream code
never, ever, has to care.

So perhaps consider using an immutable design...

Marc
 
Ray,

Serialize it and write it to disk.

Cor


Turns out whether you do a deep copy (Serialization) or shallow copy
(MemberwiseClone) the result is the same--success--if you follow the
protocol in this thread, and push/pop the state repeatedly, after
using :ICloneable as the base class for the stuff being cloned.

Trick stuff.

RL
 
So perhaps consider using an immutable design...

Marc

I'm still learning so I appreciate your feedback, and what you
consider (if it's encapsulated in a few words) as "immutable design".
I know strings are immutable, unless you use StringBuilder, but I'm
not sure what an immutable design is.

Anyway, for this project the problem was solved, after a whole day and
half the night beating out my brains trying different things (what
else is new, it's programming in C#).

RL
 
or shallow copy (MemberwiseClone)

I suspect you might run into a few issues if you are using nested data
structures... you might have captured obj.Foo, but not necessarily
obj.Bar.Something.Whatever[2].TheOther (if you see what I mean). But
if you have solved your immediate issue, then fine...

Marc
 
Marc said:
Another approach is
to work with immutable objects; immutable objects tend to be more
common in java than C# - but by definition with an immutable object
you don't need to worry about changes... your downstream code might
have a slightly different *copy* of the data, but your upstream code
never, ever, has to care.

I am not so sure Java is more into immutable than C#.

In C# structs are bring the immutable discussion on the table.

Java comes with a few immutable classes and it has also
been recommended for programmers to create immutable classes.
But that recommendation has never caught on.

Arne
 
In C# structs are bring the immutable discussion on the table.

Now if only we could stop people from creating mutable structs...

[and then asking "why doesn't this work? No: I won't change my design
- but make it work for me anyway?"]

Marc
 
Marc said:
In C# structs are bring the immutable discussion on the table.

Now if only we could stop people from creating mutable structs...

[and then asking "why doesn't this work? No: I won't change my design
- but make it work for me anyway?"]

So you want the immutable keyword:

public immutable struct FooBar {

or

public readonly struct FooBar {

?

Actually I think that could be very useful (and they should
add it to class as well).

I assume that the semantics is that only the constructor
can change the state.

I wonder if there are any implementation issues.

Arne
 
Now if only we could stop people from creating mutable structs...
[and then asking "why doesn't this work? No: I won't change my design
- but make it work for me anyway?"]

So you want the immutable keyword:

public immutable struct FooBar {

or

publicreadonlystruct FooBar {

?

Actually I think that could be very useful (and they should
add it to class as well).

I assume that the semantics is that only the constructor
can change the state.

I wonder if there are any implementation issues.

Not that I know of. Interestingly enough, there is a Connect ticket
for this feature request since 2004, presently in state "Closed
(Postponed)':

https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=91971

Go ahead and vote for it, and perhaps we'll see it implemented - not
in C# 4.0, it seems, but maybe in the version after that.
 
Back
Top