Simple question: Is having multiple 'ref' parameters allowed in the same method? For example,

private void RouletteSelection(ref Chromosome child1, ref Chromosome child2)
{
	...
        ...
        ...
}

I'm not getting any compiler or runtime errors, but the output I'm getting suggests there may be a problem with this method signature.

Thanks for your help.

Recommended Answers

All 4 Replies

Hey,

Actually it's absolutely normal, you can use multiple ref. :)

An object is passed by reference to a method, so you don't need to add ref if you want to change its value. For example,in the case you posted, let's say Chromosome has a field called "name". If you assign other values to child1 and child2 as below, when function returns, child1 and child2 will have the values modified

private void MainFunction()
{
child1.name = "Timmy";
child2.name = "Jack";
RoulletteSelection (child1, child2);
MessageBox.Show(child1.name + " " + child2.name); //the output will be "John Tom";
}

private void RouletteSelection(Chromosome child1, Chromosome child2)
{
child1.name = "John";
child2.name = "Tom";
}

Why this happens? By default, c# passes parameters by value, so for an int or string c# passes the value, but for objects you send object's reference by value. If you want to change the reference to that object, than you use have to pass it with ref keyword.

Example1 :

private void MainFunction()
{
child1.name = "Timmy";
child2.name = "Jack";
RoulletteSelection (child1, child2);
MessageBox.Show(child1.name + " " + child2.name); //the output will be "Timmy Jack" because in RouletteSelection I try to change objects reference(which is passed by value), so is the same case as passing an int without ref keyword 
}

private void RouletteSelection(Chromosome child1, Chromosome child2)
{
Chromosome child = new Chromosome();
child.name = "Santa Clause";
child1 = child;
}

Example2 :

private void MainFunction()
{
child1.name = "Timmy";
child2.name = "Jack";
RoulletteSelection (child1, child2);
MessageBox.Show(child1.name + " " + child2.name); //the output will be "Santa Jack" I changed the reference of child1 to the newly created object in RouletteSelection
}

private void RouletteSelection(ref Chromosome child1,ref Chromosome child2)
{
Chromosome child = new Chromosome();
child.name = "Santa ";
child1 = child;
}

Hope you understood something from this.
And to answer to your actual question, there is no limit of ref or out parameters for a function.

Cheers,
Ionut

*I SOLVED THIS ON MY OWN. NO NEED TO READ ALL OF THE CODE UNLESS YOU JUST WANT TO*

Hmmm, well, thanks for the info. I thought you could pass multiple ref parameters, but I wasn't sure. Since you can, then that means I have no idea what's going wrong in my code.


So, here's the part which is causing me trouble:

The ToFile(string fileName, int id) method prints out the chromosome in the proper format, and the id parameter is simply just a number which gets printed so I can tell which chromosome is which. In this case, id is set by x. Notice that RouletteSelection() is called, which takes two ref parameters, then those two chromosomes are printed upon completion of RouletteSelection(). The problem I am having is that both, child1 and child2, are printing the same results.

for (int x = 0; x < POPULATION_SIZE / 2; x++)
			{
				Chromosome child1, child2;
				child1 = child2 = new Chromosome(CHROMOSOME_LENGTH);

				RouletteSelection(ref child1, ref child2);

				using (FileStream fileStream = new FileStream(fileName, FileMode.Append))
				{
					using (StreamWriter writer = new StreamWriter(fileStream, Encoding.UTF8))
					{
						writer.Write("Child1: ");
					}
				}
				child1.ToFile(fileName, x);
				using (FileStream fileStream = new FileStream(fileName, FileMode.Append))
				{
					using (StreamWriter writer = new StreamWriter(fileStream, Encoding.UTF8))
					{
						writer.Write("Child2: ");
					}
				}
				child2.ToFile(fileName, x);
                                ...
                                ...
                        }

This is my RouletteSelection method:

private void RouletteSelection(ref Chromosome child1, ref Chromosome child2)
		{
			double target = random.NextDouble() * totalFitness;
			double subtotal = 0;
			int parentIndex = 0;

			// Randomly picks a parent chromosome based, on its fitness.
			for (int x = 0; x < POPULATION_SIZE; x++)
			{
				subtotal += parentPopulation[x].fitness;

				if (subtotal >= target)
				{
					parentPopulation[x].CopyBits(child1);
					parentIndex = x;
					subtotal = 0;
					child1.ToFile(fileName, 999);
					break;
				}
			}

			target = random.NextDouble() * totalFitness;

			// Randomly picks a unique parent chromosome, based on fitness.
			for (int x = 0; x < POPULATION_SIZE; x++)
			{
				subtotal += parentPopulation[x].fitness;

				if (subtotal >= target)
				{
					if (x == parentIndex)
					{
						x = 0;
						subtotal = 0;
						target = random.NextDouble() * totalFitness;
					}
					else
					{
						parentPopulation[x].CopyBits(child2);
						child2.ToFile(fileName, 999);
						break;
					}
				}
			}
		}

This is the RouletteSelection() method. In this chunk of code, the CopyBits(Chromosome chrom) method just copies the data from one chromosome to another. Also, id is set to 999, just so I can tell this output apart from the output in the previous chunk of code. From within RouletteSelection(), child1 and child2 print correctly.

Notice that child1 and child2 print correctly from within RouletteSelection(), and immediately I break from the method and return control to loop in the first chunk of code. As soon as control is returned to the loop, both child1 and child2 output child2's data. For example, this is the latest output I received from this code:

[DDULRRULRDUDUURDRDRDUULRDUUUULLDUDL] 999
[LDLUULRRULLUDLLRDULLUUUULLDUURRDURD] 999
Child1: [LDLUULRRULLUDLLRDULLUUUULLDUURRDURD] 0
Child2: [LDLUULRRULLUDLLRDULLUUUULLDUURRDURD] 0

The two lines that end in "999" are the ones called from within RouletteSelection(). The two lines that end in "0" are called after returning from RouletteSelection(). child1 always contains child2's data.

Can anyone tell me why that is?

Ok, nvm. I figured it out. I'm stupid for not realizing this earlier. It was this line:

child1 = child2 = new Chromosome(CHROMOSOME_LENGTH);

I was trying to save lines and instantiate them on the same line. I didn't realize that it would assign both to the same memory. Sorry for the trouble everyone.

commented: well done for finding it on your own :) +3
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.