Generic Swap difficulty - c#

I'm coming from C++ where it's easy to do something like this:
template<class T>
void Swap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
and then use it to swap values in a container:
std::vector<int> someInts;
someInts.push_back(1);
someInts.push_back(2);
Swap(someInts[0], someInts[1]);
However, upon attempting to do the same thing in C#
void Swap<T>(ref T a, ref T b)
{
T temp = a;
a = b;
b = temp;
}
I get the error "property or indexer may not be passed as an out or ref parameter"
Why is this and how can I overcome it?
Many thanks

You cannot use indexers or properties ref parameters. The reason is you are retuning a reference to the object but not the location so any effect the function would have would not actually change the source as it wouldn't write it back to the location (i.e. not call the setter in the case of a property). You need to pass the array into the method so that the method can set values an indexes as well as know what values to swap.

Properties and the indexer are actually methods (created by the compiler behind the scenes), so I suppose it is not possible to do call-by-reference on them. However you could write a method like this:
public void Swap<T>(T[] data, int a, int b) {
T temp = data[a];
data[a] = data[b];
data[b] = temp;
}
Swap(someInts, 0, 1);

Related

Pass-by-reference and ref [duplicate]

This question already has answers here:
What is the difference between 2 methods with ref object par and without?
(5 answers)
Closed 8 years ago.
I have been reading a bit the tutorials on MSDN to get my head around pass-by-reference in C#, ref and out and I came across the following code sample:
using System;
class TheClass
{
public int x;
}
struct TheStruct
{
public int x;
}
class TestClass
{
public static void structtaker(TheStruct s)
{
s.x = 5;
}
public static void classtaker(TheClass c)
{
c.x = 5;
}
public static void Main()
{
TheStruct a = new TheStruct();
TheClass b = new TheClass();
a.x = 1;
b.x = 1;
structtaker(a);
classtaker(b);
Console.WriteLine("a.x = {0}", a.x); //prints 1
Console.WriteLine("b.x = {0}", b.x); //prints 5
}
}
The note to this from the tutorial:
This example shows that when a struct is passed to a method, a copy of
the struct is passed, but when a class instance is passed, a reference
is passed.
I totally understood it, but my question is, if a reference is passed in C# to the parameter, why would they need ref as in the following sample:
void tearDown(ref myClass a)
{
a = null;
}
MyClass b = new MyClass();
this.tearDown(ref b);
assert(b == null);
//b is null
??? I thought C# was the same in C - pass-by-value.
In C#, basically all classes as pointers. However, passing by ref/out or not is like passing the pointer to a pointer or the pointer itself.
When you pass a class (as per the first sample) any changes to the classes members are carried over. However, changing the reference to the object itself would not yield the results. Say you replace
public static void classtaker(TheClass c)
{
c.x = 5;
}
With
public static void classtaker(TheClass c)
{
c = new TheClass();
c.x = 5;
}
Since c is not an out or ref paramter, you're reassigning the local pointer to c, not the value of c itself. Since you only modified the .x of the local c, the result would be that b.x == 1 after calling this modified ClassTaker.
Now, as per your second example, since a is a ref parameter, changes to the value a itself will be seen in the calling scope, as in the example, but removing the ref from the call would cause the null assertion to fail.
Basically, ref passing passes what can be thought of as a pointer to your pointer, while calling without ref/out passes a copied pointer to your object data.
EDIT:
The reason one can assign c.X in method scope is because the object c points to the object X, and you'll always get the same pointer to X regardless of the ref/out parameter or not. Instead, ref/out modifies your ability to change the value c as seen by the calling scope.

Accessing and changing structs as property vs as field

Ok, I'll start my question saying that I understand the evil behind mutable structs, but I'm working with SFML.net and using a lot of Vector2f and such structs.
What I don't get it is why I can have, and change the values of, a field in a class and can't do the same with a property, in the very same class.
Take a look at this code:
using System;
namespace Test
{
public struct TestStruct
{
public string Value;
}
class Program
{
TestStruct structA;
TestStruct structB { get; set; }
static void Main(string[] args)
{
Program program = new Program();
// This Works
program.structA.Value = "Test A";
// This fails with the following error:
// Cannot modify the return value of 'Test.Program.structB'
// because it is not a variable
//program.structB.Value = "Test B";
TestStruct copy = program.structB;
copy.Value = "Test B";
Console.WriteLine(program.structA.Value); // "Test A"
Console.WriteLine(program.structB.Value); // Empty, as expected
}
}
}
note: I'll build my own classes to cover the same functionality and keep with my mutability, but I can't see a technical reason why I can do one and can't do other.
When you access a field, you are accessing the actual struct. When you access it through property, you call a method that returns whatever is stored in the property. In the case of a struct, which is a value type, you will get back a copy of the struct. Apparently that copy is not a variable and cannot be changed.
Section "1.7 Structs" of the C# language specification 5.0 says:
With classes, it is possible for two variables to reference the same
object and thus possible for operations on one variable to affect the
object referenced by the other variable. With structs, the variables
each have their own copy of the data, and it is not possible for
operations on one to affect the other.
That explains that you will receive a copy of the struct and not be able to modify the original struct. However, it doesn't describe why it isn't allowed.
Section "11.3.3" of the specifcation:
When a property or indexer of a struct is the target of an assignment,
the instance expression associated with the property or indexer access
must be classified as a variable. If the instance expression is
classified as a value, a compile-time error occurs. This is described
in further detail in §7.17.1.
So the returned "thing" from the get accessor is a value and not a variable. That explains the wording in the error message.
The specification also contains an example in section 7.17.1 that is nearly identical to your code:
Given the declarations:
struct Point
{
int x, y;
public Point(int x, int y) {
this.x = x;
this.y = y;
}
public int X {
get { return x; }
set { x = value; }
}
public int Y {
get { return y; }
set { y = value; }
}
}
struct Rectangle
{
Point a, b;
public Rectangle(Point a, Point b) {
this.a = a;
this.b = b;
}
public Point A {
get { return a; }
set { a = value; }
}
public Point B {
get { return b; }
set { b = value; }
}
}
in the example
Point p = new Point();
p.X = 100;
p.Y = 100;
Rectangle r = new Rectangle();
r.A = new Point(10, 10);
r.B = p;
the assignments to p.X, p.Y, r.A, and r.B are permitted because p and r are variables. However, in the example
Rectangle r = new Rectangle();
r.A.X = 10;
r.A.Y = 10;
r.B.X = 100;
r.B.Y = 100;
the assignments are all invalid, since r.A and r.B are not variables.
Although properties look like variables, each property is really a combination of a get method and/or a set method. Typically a property get method will return a copy of what's in some variable or array slot, and a put method will copy its parameter into that variable or array slot. If one wants to do something like someVariable = someObject.someProeprty; or someobject.someProperty = someVariable;, it won't matter that those statements end up being executed as var temp=someObject.somePropertyBackingField; someVariable=temp; and var temp=someVariable; someObject.somePropertyBackingField=temp;, respectively. On the other hand, there are some operations which can be done with fields but cannot be done with properties.
If an object George exposes a field named Field1, then code may pass George.Field as a ref or out parameter to another method. Additionally, if the type of Field1 is a value type with exposed fields, then an attempt to access those fields will access the fields of the struct that is stored within George. If Field1 has exposed properties or methods, then accessing those will cause George.Field1 to be passed to those methods as though it were a ref parameter.
If George exposes a property named Property1, then an access of Property1 which is not the left side of an assignment operator will call the "get" method and store its result in a temporary variable. An attempt to read a field of Property1 will read that field from the temporary variable. An attempt to call a property getter or method on Property1 will pass that temporary variable as a ref parameter to that method and then discard it after the method returns. Within the method or property getter or method, this will refer to the temporary variable, and any changes the method makes to this will be discarded.
Because it would make no sense to write to fields of a temporary variable, attempts to write to fields of a property are forbidden. Additionally, present versions of the C# compiler will guess that property setters would be likely to modify this and will thus forbid any use of property setters even when they would in fact not modify the underlying structure [e.g. the reason ArraySegment includes an indexed get method and not an indexed set method is that if one were to try to say e.g. thing.theArraySegment[3] = 4; the compiler would think one was trying to trying to modify the structure returned by the theArraySegment property, rather than modify the array whose reference is encapsulated therein]. It would be extremely useful if one could specify that particular structure methods will modify this and should not be invokable on structure properties, but as yet no mechanism exists for that.
If one wants to write to a field contained within a property, the best pattern is usually:
var temp = myThing.myProperty; // Assume `temp` is a coordinate-point structure
temp.X += 5;
myThing.myProperty = temp;
If the type of myProperty is designed to encapsulate a fixed set of related but independent values (such as the coordinates of a point), it's best if it exposes those variables as fields. Although some people seem to prefer to design structs so as to require constructs like:
var temp = myThing.myProperty; // Assume `temp` is some kind of XNA Point structure
myThing.myProperty = new CoordinatePoint(temp.X+5, temp.Y);
I would regard such code as less readable, less efficient, and more error-prone than the previous style. Among other things, if CoordinatePoint happens to e.g. expose a constructor with parameters X,Y,Z as well as a constructor which takes parameters X,Y and assumes Z is zero, code like the second form would zero out Z without any indication that it was doing so (intentionally or unintentionally). By contrast, if X is an exposed field, it's much clearer that the first form would only modify X.
In some cases, it may be helpful for a class to expose an internal field or array slot via a method that passes it as a ref parameter to a user-defined routine, e.g. a List<T>-like class might expose:
delegate void ActByRef<T1>(ref T1 p1);
delegate void ActByRef<T1,T2>(ref T1 p1, ref T2 p2);
void ActOnItem(int index, ActByRef<T> proc)
{
proc(ref BackingArray[index]);
}
void ActOnItem<PT>(int index, ActByRef<T,PT> proc, ref PT extraParam)
{
proc(ref BackingArray[index], ref extraParam);
}
Code which had a FancyList<CoordinatePoint> and wanted to add some local variable dx to field X of item 5 in iit could then do:
myList.ActOnItem(5, (ref Point pt, ref int ddx) => pt.X += ddx, ref dx);
Note that this approach would allow in-place modification of data in the list, and even allow the use of such methods as Interlocked.CompareExchange). Unfortunately, there's no possible mechanism by which a type which derives from List<T> can support such a method, and no mechanism by which a type which does support such a method can be passed to code which expects a List<T>.

How to assign to a list of variables in one statement

Perl has the ability to do:
my ($a,$b,$c,$d) = foo();
where foo returns 4 variables, as opposed to assigning it one at a time. Is there something similar in C#?
No, basically. Options:
object[] values = foo();
int a = (int)values[0];
string b = (string)values[1];
// etc
or:
var result = foo();
// then access result.Something, result.SomethingElse etc
or:
int a;
string b;
float c; // using different types to show worst case
var d = foo(out a, out b, out c); // THIS WILL CONFUSE PEOPLE and is not a
// recommendation
Tuple can be a useful construct for this.
public Tuple<int, string, double> Foo() { ... }
Then you can do:
var result = Foo();
int a = result.Item1;
string b = result.Item2;
double c = result.Item3;
This is a legacy of the increasing influence of functional programming styles on C#: the tuple is a fundamental construct in many functional languages, and greatly assists in their static typing.
For functions you must return either 1 object or void. But you can approach this problem several ways.
You can create a data structure such as a struct or a class that will contain a,b,c,d and return that as your function e.g. data foo() data will contain a,b,c,d
You can use the out keyword in the parameter of your function e.g. foo(out a, out b, out c, out d), but your variable inputs will need to be initialized. More info here. See http://msdn.microsoft.com/en-us/library/t3c3bfhx(v=vs.80).aspx
You can also use ref which is similiar to out. See http://msdn.microsoft.com/en-US/library/14akc2c7(v=vs.80).aspx
Or if a,b,c,d are all the same type you can return them in the form of a collection as an arrray or a list as another member has pointed out
Also remember depending on the type that you are passing strcut vs objects that you value may be passed as a Value or Reference. See http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.71).aspx

Why Can I Change Struct's int[] Property from Method Without Specifying "ref"?

From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this. Can someone please explain why I can change the values stored in the int[]?
private void DoIt(){
SearchInfo a = new SearchInfo();
a.Index = 1;
a.Map = new int[] { 1 };
SearchInfo b = new SearchInfo();
b.Index = 1;
b.Map = new int[] { 1 };
ModifyA(a);
ModifyB(ref b);
Debug.Assert(a.Index == 1);
Debug.Assert(a.Map[0] == 1, "why did this change?");
Debug.Assert(b.Index == 99);
Debug.Assert(b.Map[0] == 99);
}
void ModifyA(SearchInfo a) {
a.Index = 99;
a.Map[0] = 99;
}
void ModifyB(ref SearchInfo b) {
b.Index = 99;
b.Map[0] = 99;
}
struct SearchInfo {
public int[] Map;
public int Index;
}
In C#, references are passed by value. An array is not copied when passed to method or when stored in an instance of another class. - a reference to the array is passed. This means a method which recieves a reference to an array (either directly or as part of another object) can modify the elements of that array.
Unlike languages like C++, you cannot declare "immutable" arrays in C# - you can however uses classes like List which have readonly wrappers available to prevent modification to the collection.
From a method, I can pass a struct which contains an array of integers, and change the values in the array. I am not sure I understand fully why I can do this.
An array is defined as a collection of variables.
Variables, by definition, can be changed. That is why we call them "variables".
Therefore when you pass an array, you can change the contents; the contents of an array are variables.
Why can I change a struct’s int[] property without specifying “ref”?
Remember, as we discussed before in a different question, you use ref to make an alias to a variable. That is what "ref" is for -- making aliases to variables. (It is unfortunate that the keyword is the confusing "ref" -- it probably would have been more clear to make it "alias".)
From MSDN:
Do not return an internal instance of an array. This allows calling code to change the array. The following example demonstrates how the array badChars can be changed by any code that accesses the Path property even though the property does not implement the set accessor.
using System;
using System.Collections;
public class ExampleClass
{
public sealed class Path
{
private Path(){}
private static char[] badChars = {'\"', '<', '>'};
public static char[] GetInvalidPathChars()
{
return badChars;
}
}
public static void Main()
{
// The following code displays the elements of the
// array as expected.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
Console.WriteLine();
// The following code sets all the values to A.
Path.GetInvalidPathChars()[0] = 'A';
Path.GetInvalidPathChars()[1] = 'A';
Path.GetInvalidPathChars()[2] = 'A';
// The following code displays the elements of the array to the
// console. Note that the values have changed.
foreach(char c in Path.GetInvalidPathChars())
{
Console.Write(c);
}
}
}
You cannot correct the problem in the preceding example by making the badChars array readonly (ReadOnly in Visual Basic). You can clone the badChars array and return the copy, but this has significant performance implications.
Although your SearchInfo struct is a value type, the .Map field is holding a reference, because Array is a reference type. Think of this reference as the address pointing to the memory location where the array resides.
When you pass an instance of SearchInfo to a method, as you know, the SearchInfo gets copied. And the copy naturally contains the very same address pointing to the very same array.
In other words, copying the struct doesn't make a copy of the array, it just makes a copy of the pointer.
Well, it is passed by reference anyway, like all reference types in C#.
Neither C# nor CLR support constness, unfortunately, so the platform doesn't really know if you are allowed to change it or not. So, it has the reference, it may use it to change the value, and there's nothing to stop it from doing so.
You may see it as a language design bug, btw. It is unexpected for the user.

Strange behaviour with incrementing int when using Action<> delegate

Given the code below:
class Sample
{
public static void Run()
{
int i = 1;
Action<int> change = Increment();
for (int x = 0; x < 5; x++ )
{
change(i);
Console.WriteLine("value=" + i.ToString());
}
}
public static Action<int> Increment()
{
return delegate(int i) { i++; };
}
}
I get the answer:
value=1
value=1
value=1
value=1
value=1
value=1
Instead of 1, 2, 3 ... 6.
This is from an article on the net with links to clues but I can't work out why this is. Anyone have any ideas?
Your parameter is being passed by value.
Writing i++ will change the value of i to a different int value (unlike a mutable type).
When you write i++ inside the delegate, you're changing the parameter to be equal to a different int value. However, this does not affect the local variable whose value was copied to the parameter.
To solve this, you need to make a delegate with a ref parameter. ref parameters are passed by reference. Therefore, when you change a ref int parameter to a different int value, you'll also change the local variable or field whose reference was passed as the parameter.
For more information, see here.
Since the Action delegates do not take ref parameters, you'll need to make your own delegate type, like this:
delegate void RefAction<T>(ref T param);
The datatype int is a primitive data type and hence a value-type as opposed to a reference type. This means that when you pass variable i to a function it isn't the actual variable that has been passed but instead a copy of the value. And therefore when the parameter is changed inside the function it is the local copy that has been changed and no the original variable.
If you are certain you want the function to be able to modify the value of the original variable, then you should add the ref keyword to the function parameter signature to tell the compiler that you want to pass the variable as a reference.
public void ChangeOriginal(ref int something)
{ something = something + 1;}
public void ChangeLocalCopy(int something)
{something = something + 1;}
I suggest you read up upon the stack vs the heap (value-type vs reference-type) since it's a very fundamental subject when programming.
the Action returns nothing. Its only incrementing the value passed in - not the reference to the orginal (as Slaks says). You can use a Func to do in this way.
class Sample
{
public static void Run()
{
int i = 1;
Func<int, int> change = Increment();
for (int x = 0; x < 5; x++ )
{
i = change(i);
Console.WriteLine("value=" + i.ToString());
}
}
public static Func<int, int> Increment()
{
return delegate(int i) { return ++i; };
}
}

Categories