Chryso


Hello

For the purpose of the question I ll use stuff that may look stupid.

Lets say you have the following structure:

struct myStruct{
public object myObj;
}

Now lets declare a list like this:
List<myStruct> myListOfStruct = new List<myStruct>();
and a temporary holder
myStruct tmpMyStruct = new myStruct();

Now lets iterate through the list

for (int i=0;i< myListOfStruct.Count;i++) {
tmpMyStruct = myListOfStructIdea;

}


Question is:
When assigning the value of the list to the temporary holder. Will the object be copied in memory, or will the reference of the object be copied to the temporary holder so that:
myListOfStructIdea.myObj and tmpMyStruct.myObj will point to the exact same spot in memory

Regards,

Chryso


Re: Boxing information required

Peter Ritchie


By "Will the object be copied in memory, or will the reference of the object be copied...", I assume you're talking about the myObj member. The reference is copied, so despite the structures getting copied you can modify the contents of myObj and it will be seen by all copies of the structure.






Re: Boxing information required

Chryso

Thank you for the answer.

Regards,
Chryso





Re: Boxing information required

DaveGwynSmith

Hi Chryso

1) You need to set myObj - at the moment its null.

2) You need to add to your list - currently it's Count is 0.

3) I think, because a structure is a 'value' type - your "myobj"s will not have the same spot in memory.

4) Where does the 'boxing' come in

cheers

dave





Re: Boxing information required

Chryso

Hi Dave

The object is set and the list has a count of over 0, did not add those for the purpose of the thread.

3) the holder will not be in the same memory place, but I was wondering about the reference it would be containing. From the previous reply I get it that the references would be the same.

4) Isn't boxing the action of putting objects inside structures or objects (If not gotta go check my def of boxing)

Regards,
Chryso




Re: Boxing information required

DaveGwynSmith

hi chryso

4)

Values of reference types are treated as objects simply by viewing the values as type object. Values of value types are treated as objects by performing boxing and unboxing operations. In the following example, an int value is converted to object and back again to int.

using System;

class Test
{
static void Main() {
int i = 123;
object o = i; // Boxing
int j = (int)o; // Unboxing
}
}

When a value of a value type is converted to type object, an object instance, also called a ¡°box,¡± is allocated to hold the value, and the value is copied into that box. Conversely, when an object reference is cast to a value type, a check is made that the referenced object is a box of the correct value type, and, if the check succeeds, the value in the box is copied out.





Re: Boxing information required

Chryso

Hi,

Well, that is what I call casting.

So what is the difference between casting and boxing And if they are the same, why use 2 differents words

Precision: I am not english so keeping it simple is better because your first sentence is really really hard to understand for me. If I understand right, you are saying reference type have as a type: object .

Regards,
Chryso




Re: Boxing information required

DaveGwynSmith

Hi Chryso

Regarding point 3.

Code Snippet

public static void BoxingTest()

{

List<myStruct> myListOfStruct = new List<myStruct>();

myStruct tmpMyStruct = new myStruct();

tmpMyStruct.myObj = 7;

myListOfStruct.Add(tmpMyStruct);

tmpMyStruct.myObj = "gfgfgf";

myListOfStruct.Add(tmpMyStruct);

for (int i = 0; i < myListOfStruct.Count; i++)

{

tmpMyStruct = myListOfStruct[i]; (a)

tmpMyStruct.myObj = "fdfddsdsd"; (b)

}

}

When I debug this:

After point (b)

myListOfStruct[0].myObj = 7 and tmpMyStruct.myObj = "fsfddsdsd".

myListOfStruct[1].myObj = "gfgfgf" and tmpMyStruct.myObj = "fsfddsdsd".

Can you show more detail of your code

cheers

dave





Re: Boxing information required

Chryso

Hello,

Sure but it is long... and I am having a hard time with the code snipper so I ll just paste it here

List of structures used:
public struct AIChromosom
{
public int numberOfDeath;
public int numberOfVictory;
public List<float> moveGenom;
public List<float> offensiveGenom;
public List<float> defensiveGenom;
public SortedList<int, float> spellEfficiency;
}

public struct AIMonsterType
{
public int mobType;
public List<AIChromosom> chromosomPool;
}

List of methods used:

AIMonsterType tmpAIMonsterType;
public void monsterEvolution()
{
chromosomSort();

for (int i = 0; i < AIMonsterList.Count; i++)
{
//tmpAIMonsterType.mobType = AIMonsterListIdea.mobType;
//tmpAIMonsterType.chromosomPool = AIMonsterListIdea.chromosomPool;

tmpAIMonsterType = AIMonsterListIdea;

#region Validity Check
for (int l = 0; l < i; l++)
{
for (int j = 0; j < AIMonsterList.Values[l].chromosomPool.Count; j++)
{
bool spellEfficiencyIsCorrect = true;
if (j + 1 < AIMonsterList.Values[l].chromosomPool.Count)
{
for (int k = 0; k < AIMonsterList.Values[l].chromosomPool[j].spellEfficiency.Count; k++)
{
if (AIMonsterList.Values[l].chromosomPool[j].spellEfficiency.Keys[k]
!= AIMonsterList.Values[l].chromosomPool[j + 1].spellEfficiency.Keys[k])
{
spellEfficiencyIsCorrect = false;
}
}
if (!spellEfficiencyIsCorrect)
{
;
}
}
}
}
#endregion


List<AIChromosom> tmpAICList = chromosomEvolution(tmpAIMonsterType.chromosomPool);

#region Validity Check
for (int l = 0; l < AIMonsterList.Count; l++)
{
if (i != l)
{
for (int j = 0; j < AIMonsterList.Values[l].chromosomPool.Count; j++)
{
bool spellEfficiencyIsCorrect = true;
if (j + 1 < AIMonsterList.Values[l].chromosomPool.Count)
{
for (int k = 0; k < AIMonsterList.Values[l].chromosomPool[j].spellEfficiency.Count; k++)
{
if (AIMonsterList.Values[l].chromosomPool[j].spellEfficiency.Keys[k]
!= AIMonsterList.Values[l].chromosomPool[j + 1].spellEfficiency.Keys[k])
{
spellEfficiencyIsCorrect = false;
}
}
if (!spellEfficiencyIsCorrect)
{
;
}
}
}
}
}
#endregion

tmpAIMonsterType.chromosomPool = tmpAICList;

AIMonsterListIdea = tmpAIMonsterType;
}
}

int maxCutIndex;
int chromosomMiddleIndex;
int cutIndex;
float mutationRate = 0.01f; //1%

/// <summary>
/// Modifies the chromosom list by mixing good chromosoms together
/// </summary>
/// <param name="chromosomList"></param>
/// <returns></returns>
private List<AIChromosom> chromosomEvolution(List<AIChromosom> chromosomList)
{
#region Chromosom Size
maxCutIndex = chromosomList[0].spellEfficiency.Count
+ chromosomList[0].defensiveGenom.Count
+ chromosomList[0].offensiveGenom.Count
+ chromosomList[0].moveGenom.Count;
#endregion

//chromosomMiddleIndex = chromosomList.Count / 2;

for (int i = 0; i < chromosomMiddleIndex; i++)
{
cutIndex = Game1.random.Next(0, maxCutIndex);

//If we are not out of the array (should not happen, but just in case we check)
if (2 * i + 1 < chromosomList.Count
&& 2 * i < chromosomList.Count)
{
chromosomList[2 * i] = chromosomMix(chromosomListIdea, chromosomList[i + 1]);
chromosomList[2 * i + 1] = chromosomMix(chromosomList[i + 1], chromosomListIdea);
}
}

return chromosomList;
}

/// <summary>
/// Mixes 2 chromosoms
/// </summary>
/// <param name="chromosom1"></param>
/// <param name="chromosom2"></param>
/// <param name="cutIndex"></param>
/// <returns></returns>
int currentIndex;
List<AIChromosom> tmpChromosomList = new List<AIChromosom>();
int tmpChromosomIndex;
List<float> tmpFloatList = new List<float>();
SortedList<int, float> tmpFloatSortedList = new SortedList<int, float>();
private AIChromosom chromosomMix(AIChromosom chromosom1, AIChromosom chromosom2)
{
#region New Chromosom Initialization
AIChromosom tmpChromosom = new AIChromosom();
tmpChromosom.defensiveGenom = new List<float>();
tmpChromosom.moveGenom = new List<float>();
tmpChromosom.offensiveGenom = new List<float>();
tmpChromosom.spellEfficiency = new SortedList<int, float>();
#endregion

#region Chromosom List initialization
//Instead of having to type chromosom1, chromosom2 and so on all the time we use
//A simple index to know from which one we need to take the information we need
tmpChromosomList.Clear();
tmpChromosomList.Add(chromosom1);
tmpChromosomList.Add(chromosom2);
tmpChromosomIndex = 0;
#endregion

currentIndex = 0;

#region SpellEfficiency Region
if (cutIndex < chromosom1.spellEfficiency.Count)
{
//If the cut index is in the spellefficency genom
tmpFloatSortedList.Clear(); //We clean up the temporary float list that will hold the data
for (int i = 0; i < chromosom1.spellEfficiency.Count; i++)
{
if (currentIndex + i == cutIndex)
{
//If we are at the cut index
tmpChromosomIndex = 1;
}
//We save the value into the temporary list
tmpFloatSortedList.Add(tmpChromosomList[tmpChromosomIndex].spellEfficiency.KeysIdea,
tmpChromosomList[tmpChromosomIndex].spellEfficiency.ValuesIdea);
}
//We update the list of the new chromosom with the temporary list
tmpChromosom.spellEfficiency = tmpFloatSortedList;
}
else
{
tmpChromosom.spellEfficiency = tmpChromosomList[tmpChromosomIndex].spellEfficiency;
}

currentIndex += tmpChromosom.spellEfficiency.Count;
#endregion

#region DefensiveGenom Region
if (cutIndex < currentIndex + chromosom1.defensiveGenom.Count && cutIndex >= currentIndex)
{
tmpFloatList.Clear();
for (int i = 0; i < chromosom1.defensiveGenom.Count; i++)
{
if (currentIndex + i == cutIndex)
{
tmpChromosomIndex = 1;
}
tmpFloatList.Add(tmpChromosomList[tmpChromosomIndex].defensiveGenomIdea);
}
tmpChromosom.defensiveGenom = tmpFloatList;
}
else
{
tmpChromosom.defensiveGenom = tmpChromosomList[tmpChromosomIndex].defensiveGenom;
}

currentIndex += tmpChromosom.defensiveGenom.Count;
#endregion

#region OffensiveRegion
if (cutIndex < currentIndex + chromosom1.offensiveGenom.Count && cutIndex >= currentIndex)
{
tmpFloatList.Clear();
for (int i = 0; i < chromosom1.offensiveGenom.Count; i++)
{
if (currentIndex + i == cutIndex)
{
tmpChromosomIndex = 1;
}
tmpFloatList.Add(tmpChromosomList[tmpChromosomIndex].offensiveGenomIdea);
}
tmpChromosom.offensiveGenom = tmpFloatList;
}
else
{
tmpChromosom.offensiveGenom = tmpChromosomList[tmpChromosomIndex].offensiveGenom;
}
currentIndex += tmpChromosom.offensiveGenom.Count;
#endregion

#region MoveGenom Region
if (cutIndex < currentIndex + chromosom1.moveGenom.Count && cutIndex >= currentIndex)
{
tmpFloatList.Clear();
for (int i = 0; i < chromosom1.moveGenom.Count; i++)
{
if (currentIndex + i == cutIndex)
{
tmpChromosomIndex = 1;
}
tmpFloatList.Add(tmpChromosomList[tmpChromosomIndex].moveGenomIdea);
}
tmpChromosom.moveGenom = tmpFloatList;
}
else
{
tmpChromosom.moveGenom = tmpChromosomList[tmpChromosomIndex].moveGenom;
}
currentIndex += tmpChromosom.moveGenom.Count;
#endregion

return tmpChromosom;
}


Here is the code that is posing me some problems.

I left 2 validity check regions. In the second region I some times get errors. But Not errors on the current monsterType I am evolving. Errors come from the other monsterTypes... Which is plain weird because chromosomEvolution() does not access the value of those elements.

And I am trying to understand how it could happen. Though for the last 7 tries I haven't been able to make it bug again.

Regards,
Chryso




Re: Boxing information required

DaveGwynSmith

Sorry Chryso,

I forgot to say this is an extract from the Microsoft C# specification.

That was from the introduction.

Here's a bit more detail:

4.3 Boxing and unboxing

The concept of boxing and unboxing is central to C#¡¯s type system. It provides a bridge between value-types and reference-types by permitting any value of a value-type to be converted to and from type object. Boxing and unboxing enables a unified view of the type system wherein a value of any type can ultimately be treated as an object.

4.3.1 Boxing conversions

A boxing conversion permits a value-type to be implicitly converted to a reference-type. The following boxing conversions exist:

¡¤ From any value-type (including any enum-type) to the type object.

¡¤ From any value-type (including any enum-type) to the type System.ValueType.

¡¤ From any value-type to any interface-type implemented by the value-type.

¡¤ From any enum-type to the type System.Enum.

Boxing a value of a value-type consists of allocating an object instance and copying the value-type value into that instance.

The actual process of boxing a value of a value-type is best explained by imagining the existence of a boxing class for that type. For any value-type T, the boxing class behaves as if it were declared as follows:

sealed class T_Box: System.ValueType
{
T value;

public T_Box(T t) {
value = t;
}
}

Boxing of a value v of type T now consists of executing the expression new T_Box(v), and returning the resulting instance as a value of type object. Thus, the statements

int i = 123;
object box = i;

conceptually correspond to

int i = 123;
object box = new int_Box(i);

Boxing classes like T_Box and int_Box above don¡¯t actually exist and the dynamic type of a boxed value isn¡¯t actually a class type. Instead, a boxed value of type T has the dynamic type T, and a dynamic type check using the is operator can simply reference type T. For example,

int i = 123;
object box = i;
if (box is int) {
Console.Write("Box contains an int");
}

will output the string ¡°Box contains an int¡± on the console.

A boxing conversion implies making a copy of the value being boxed. This is different from a conversion of a reference-type to type object, in which the value continues to reference the same instance and simply is regarded as the less derived type object. For example, given the declaration

struct Point
{
public int x, y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

the following statements

Point p = new Point(10, 10);
object box = p;
p.x = 20;
Console.Write(((Point)box).x);

will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p to box causes the value of p to be copied. Had Point been declared a class instead, the value 20 would be output because p and box would reference the same instance.

4.3.2 Unboxing conversions

An unboxing conversion permits a reference-type to be explicitly converted to a value-type. The following unboxing conversions exist:

¡¤ From the type object to any value-type (including any enum-type).

¡¤ From the type System.ValueType to any value-type (including any enum-type).

¡¤ From any interface-type to any value-type that implements the interface-type.

¡¤ From the type System.Enum to any enum-type.

An unboxing operation consists of first checking that the object instance is a boxed value of the given value-type, and then copying the value out of the instance.

Referring to the imaginary boxing class described in the previous section, an unboxing conversion of an object box to a value-type T consists of executing the expression ((T_Box)box).value. Thus, the statements

object box = 123;
int i = (int)box;

conceptually correspond to

object box = new int_Box(123);
int i = ((int_Box)box).value;

For an unboxing conversion to a given value-type to succeed at run-time, the value of the source operand must be a reference to an object that was previously created by boxing a value of that value-type. If the source operand is null, a System.NullReferenceException is thrown. If the source operand is a reference to an incompatible object, a System.InvalidCastException is thrown.

dave




Re: Boxing information required

DaveGwynSmith

Hi Chryso

Your code is very impressive.

Unable to build it (parts missing) so hard to find issue.

Will try again tomorow.

Getting back to your original question. I think you are doing an implicit box. Because you are using a structure, your object member will be copied and will point to a different memory location.

"A boxing conversion implies making a copy of the value being boxed. .... For example, given the declaration

struct Point
{
public int x, y;

public Point(int x, int y) {
this.x = x;
this.y = y;
}
}

the following statements

Point p = new Point(10, 10);
object box = p;
p.x = 20;
Console.Write(((Point)box).x);

will output the value 10 on the console because the implicit boxing operation that occurs in the assignment of p to box causes the value of p to be copied. Had Point been declared a class instead, the value 20 would be output because p and box would reference the same instance." C#Spec, Microsoft

regards

dave





Re: Boxing information required

Chryso

Hello,

You will find a more complete file here:
http://teuhsjbs.free.fr/Perso/Evolution.rar

I had to cut / modify some stuff since some other pieces are missing to.

Though, what is the difference between casting and boxing

Regards,
Chryso




Re: Boxing information required

DaveGwynSmith

Hi Chryso

I've build your evolution class.

What methods do I call to run it and what error am I on the lookout for

Casting applies to all types.

Boxing is like casting but only applies to the Object class. (You are not using the Object class directly so I would not worry too much about it.)

cheers

dave





Re: Boxing information required

Chryso

Hello,

Well one needs to load the xml file, then use monsterEvolution() to make the chromosom evolve.

Since I have those check region to catch an error you need to put breakpoints in:
if (!spellEfficiencyIsCorrect)
{
;
}
(all of them)

It is not something that happens 100% of the time. But when it happens you will see that some chromosoms do not have the same spellEfficiency Keys which is not something that should happen.

Thank you for the time you are spending on this. Though, it has not buggued in a while here and I still do not understand why it does not bug anymore.

Regards,
Chryso




Re: Boxing information required

Chryso

Mr Ritchie was the right one.

Here is an exemple of how stuff can go wrong:


Code Snippet

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace Boxing_Test
{
class Program
{
static void Main(string[] args)
{
somePublicClass myClass = new somePublicClass();
Thread secondThread = new Thread(new ThreadStart(myClass.SecondThread));
secondThread.Start();
Console.WriteLine("Init...");
Thread.Sleep(1000);
mySecondStruct struct2 = new mySecondStruct();

for (int i = 0; i < 5; i++)
{
struct2 = new mySecondStruct();
struct2.myInt = i;
struct2.myIntList = new List<int>();

for (int j = 0; j < i; j++)
struct2.myIntList.Add(j);

myClass.SendPacket(struct2, i, i);
}
}
}

public struct mySecondStruct
{
public int myInt;
public List<int> myIntList;
}

public class somePublicClass
{
OriginActionTarget myCurrentPacket;
List<OriginActionTarget> myBuffer = new List<OriginActionTarget>();
object buffLock = new object();

public void SecondThread()
{
while (true)
{
if (myBuffer.Count > 0)
readFromMyBuffer();
}
}

public void readFromMyBuffer()
{
lock (buffLock)
{
myCurrentPacket = myBuffer[0];
myBuffer.RemoveAt(0);
}

//Thread.Sleep(1000);

Console.WriteLine("ST -- Action: {0} \t Object: {1} \t Target: {2}"
, ((mySecondStruct)myCurrentPacket.Action).myIntList.Count.ToString()
, myCurrentPacket.Origin.ToString()
, myCurrentPacket.Target.ToString());

}

public void writeToMyBuffer(OriginActionTarget Obj)
{
lock (buffLock)
{
myBuffer.Add(Obj);
}
}

public void SendPacket(object Action, object Origin, object Target)
{
OriginActionTarget packet = new OriginActionTarget();
packet.Action = Action;
packet.Origin = Origin;
packet.Target = Target;

writeToMyBuffer(packet);

Console.WriteLine("MT -- Action: {0} \t Object: {1} \t Target: {2}"
, ((mySecondStruct)packet.Action).myIntList.Count.ToString()
, packet.Origin.ToString()
, packet.Target.ToString());

((mySecondStruct)packet.Action).myIntList.Clear();

}
}

public struct OriginActionTarget
{
public object Origin;
public object Target;
public object Action;
}

}


And now, I am so screwed ....

Dammit

Thx for the help

Regards,
Chryso