Consider the TranslateAllCoords static function:
static class CoordinateTransformation
{
public static void TranslateAllCoords(ref int x, ref int y, ref int z,
int amount)
{
x+=amount;
y+=amount;
z+=amount;
}
}
Then, later in code, you have:
int x=0, y=0, z=0;
...
CoordinateTransformation.TranslateAllCoords(ref x, ref y, ref z, 5);
...
But, by calling TranslateAllCoords you are in effect modifying value types (i.e., the integer coords) and generally values types should be immutable. Are some rules broken here or is this a perfectly valid construct that gets around the "value types should be immutable" construct by modifying only built in value types?
The values are immutable. The variables that contain the value types are mutable. Variables vary, that's why they're called "variables".
The design guidance that value types should be immutable is essentially saying that you should not try to change only part of a variable. When you say
struct Point { public int X; public int Y; public int Z; }
...
Point p = new Point();
p.X = 123;
then what you are saying is "mutate only part of the variable p". That is confusing. The variable p should logically represent a point, and a point is a value. If you want to vary p, then logically vary the whole thing by assigning a new point to it. Don't mutate one point into another.
But even if we made point immutable:
struct Point { public int X { get; private set; } ... etc }
then a variable of that type can still vary!
Point p = new Point(123, 456, 789);
p = new Point(100, 200, 300);
But now it is clear that the entire variable is changing to a new point, rather than us trying to mutate a particular portion of the variable.
With an immutable value type you can then do your translation more sensibly:
static Point Translate(Point p, int offset)
{
return new Point(p.X + offset, p.Y + offset, p.Z + offset);
}
...
Point p = new Point(100, 200, 300);
p = Translate(p, 5);
See, again, p mutates, but it mutates all at once, not in little bits at a time.
No rules are broken there. You're simply creating a new integer value and reassigning the variable containing them.
Related
Just wondering cause I often find myself giving input like coordinates (X, Y) and was wondering which case is better.
If I store 3 int in one array I have a reduction of the code to 1/3, but are there more reason to prefer array over multiple vars?
Example to clarify:
int[] coord = new int[2];
coord[0] = 3;
coord[1] = 2;
or
int x = 3;
int y = 2;
I'd say that if the coordinates are so tightly coupled that you always pass both of them together (which I believe to be true), you can create a struct to encapsulate them.
public struct Coords
{
private int x;
private int y;
public Coords(int x, int y)
{
this.x = x;
this.y = y;
}
public int X
{
get { return x; }
}
public int Y
{
get { return y; }
}
}
In such scenario you can pass it like this:
var c = new Coords(1, 2);
MyMethod(c);
You have an optimization tag attached to your question, but if the problem is not critical to your application's performance, I'd go with readability/design over nanoseconds.
It kinda depens on what you're using the values for.
If you're holding a ton of values, like in a game, you should make it easily readable for yourself and maybe other coders and clarify what a value means.
You shouldn't hold many values in one array, like say HP, MP, speed, rotation, height, width,... and not clarifying what they are.
But you should say HP=100; MP=80, ...
In cases like this, there's almost everytime a 'player' class though.
That class contains player.hitpoints, player.magicpoints, player.speed, ...
But for coordinates, what I think programmers use is an array with x, y (and sometime z) coordinates.
Does the order in which I set properties using the object initializer syntax get executed in the exact same order?
For instance if I do this:
var s = new Person { FirstName = "Micah",
LastName = "Martin",
IsLoaded = true
}
will each property get set in the same order?
Yes.
Apologies for getting interrupted (I have to actually do some work every so often). The spec doesn't explicitly say it, but it makes it pretty clear IMO in section 7.6.10.2:
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas.
(Note the word "sequence" here, rather than "set". I personally think that's significant, as a sequence is ordered.)
The following class represents a point with two coordinates:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
An instance of Point can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
which has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
where __a is an otherwise invisible and inaccessible temporary variable.
EDIT: I've had a response from Mads Torgersen, who has basically said that anything which can be done now will preserve the order. There may be some oddities in future where the order is not preserved in weird cases where you're doing something other than setting a property/field, but that will depend on where the language goes.
It's worth pointing out that there are actually lots of steps going on here - there's the order of execution of the evaluation of the arguments (i.e. the RHS bits) and the order of execution of the assignments. For example, if you have:
new Foo
{
A = X,
B = Y
}
all the following orders are possible while still maintaining the order of the actual property execution (A and B):
Evaluate X, assign to A, evaluate Y, assign to B
Evaluate X, evaluate Y, assign to A, assign to B
Evaluate Y, evaluate X, assign to A, assign to B
I believe the first option is the one actually taken, but this was just to demonstrate that there's more to it than meets the eye.
I would also be very wary of actually writing code which depends on this...
I'm using C# XNA and I found when trying to add two points together it won't let me. Is there some way I can add to the Point class to allow this code to run.
Point a = new Point(3,4);
Point b = new Point(6,2);
Point c = a + b; //Should equal new Point(9,6);
You could simply overload the + operator - like this:
class Point
{
public int X { get; private set; }
public int Y { get; private set; }
public Point(int x, int y)
{
X = x;
Y = y;
}
public static Point operator +(Point p1, Point p2)
{
return new Point(p1.X + p2.X, p1.Y + p2.Y);
}
}
Now, your code compiles as work as you expect it to:
Point a = new Point(3, 4);
Point b = new Point(6, 2);
Point c = a + b; //Should equal new Point(9,6); - and it is :)
More info on operator overloading can be found on MSDN.
Add to a separate class.
public static void Add(this Point a, Point b){
a.X += b.X;
a.Y += b.Y;
}
You could use extension methods as shown below
class Program
{
static void Main(string[] args)
{
Point a = new Point(1, 2);
Point b = new Point(2, 4);
Point c=a.AddPoints(b);
}
}
public static class MyExtensions
{
public static Point AddPoints(this Point x, Point y)
{
return new Point(x.X + y.X, x.Y + y.Y);
}
}
Technically, you could use a static method, extension method and maybe even an operator overload, as other answers suggest.
However, .NET has both Point and Size to capture a semantic distinction:
Point refers to a point, usually compared to an arbitrary reference point.
Size refers to a vector - distance with a direction, or distance X & distance Y.
Adding Points would be meaningless. For example, if Points refer to coordinates on a geographic map - what would their mean? "50° latitude" + "60° latitude" = "110° latitude"? That's why .NET wisely chose not to implement an addition operator.
However, adding Point and Size can have reasonable meaning - "50° latitude" + "1° latitude distance" = "51° latitude" is a good answer.
PS. Notice the similarity to the distinction between DateTime and TimeSpan.
TL;DR - One or both of your Points should actually be a Size - change it at the earliest location possible.
You can add a Size struct to a Point struct , and easily convert between them by passing a Point in to a Size constructor like this:
c = a + (new Size(b));
Why DOT NET choose to enforce this subtle distinction between intensive and extensive tuples is beyond me.
Does the order in which I set properties using the object initializer syntax get executed in the exact same order?
For instance if I do this:
var s = new Person { FirstName = "Micah",
LastName = "Martin",
IsLoaded = true
}
will each property get set in the same order?
Yes.
Apologies for getting interrupted (I have to actually do some work every so often). The spec doesn't explicitly say it, but it makes it pretty clear IMO in section 7.6.10.2:
An object initializer consists of a sequence of member initializers, enclosed by { and } tokens and separated by commas.
(Note the word "sequence" here, rather than "set". I personally think that's significant, as a sequence is ordered.)
The following class represents a point with two coordinates:
public class Point
{
int x, y;
public int X { get { return x; } set { x = value; } }
public int Y { get { return y; } set { y = value; } }
}
An instance of Point can be created and initialized as follows:
Point a = new Point { X = 0, Y = 1 };
which has the same effect as
Point __a = new Point();
__a.X = 0;
__a.Y = 1;
Point a = __a;
where __a is an otherwise invisible and inaccessible temporary variable.
EDIT: I've had a response from Mads Torgersen, who has basically said that anything which can be done now will preserve the order. There may be some oddities in future where the order is not preserved in weird cases where you're doing something other than setting a property/field, but that will depend on where the language goes.
It's worth pointing out that there are actually lots of steps going on here - there's the order of execution of the evaluation of the arguments (i.e. the RHS bits) and the order of execution of the assignments. For example, if you have:
new Foo
{
A = X,
B = Y
}
all the following orders are possible while still maintaining the order of the actual property execution (A and B):
Evaluate X, assign to A, evaluate Y, assign to B
Evaluate X, evaluate Y, assign to A, assign to B
Evaluate Y, evaluate X, assign to A, assign to B
I believe the first option is the one actually taken, but this was just to demonstrate that there's more to it than meets the eye.
I would also be very wary of actually writing code which depends on this...
In C#, I have a simple 3D vector class.
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a;
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
the output is,
vector a= 10, 5, 10
vector b= 10, 5, 10
I assign a before i change a.x to 10. So i was expecting
vector a= 10, 5, 10
vector b= 0, 5, 10
From what i understand = operator assigns a reference to object like a pointer?
And in C# i cant overload = operator.
Do i have to manually assign each property?
Yes, because Vecor3D is a class this is quite correct.
Classes are reference types and your b = a; statement does not copy a Vector3D instance but a reference to an instance.
If you want to 'clone' the instances, you could add the IClonable interface, but that is more or less abandoned.
A better solution for an <X,Y,Z> type might be to make it a struct. Structs are values types and the meaning of b = a; would change (towards what you want).
A 3D point meets all the criteria for a struct (small, no identity). The preferred way is to design it as immutable.
Yes, "= operator assigns a reference to object like a pointer", as you put it. Thus, both a and b reference the same single object in memory. (The object previously referenced by b is not referenced any more and will be garbage collected.)
There are multiple ways to overcome this problem:
Make Vector3D a struct instead of a class. Structs are value types instead of reference types, so b = a copies the contents of a to variable b.
Implement a Clone method in your Vector3D class (previously, this would mean implementing ICloneable, but this is no longer recommended). Alternatively, you could create a Vector3D constructor that takes another vector as a parameter and creates a copy.
Manually copy the three values yourself (b = new Vector3D(a.x, a.y, a.z)), if you cannot change the implementation of Vector3D.
You may want to change your Vector3D class to a struct. That would let you work with a value type instead of a reference type.
Your other option is to implement ICloneable or use some other method to create a deep copy of your object.
Yes, reference types are assinged by reference.
If you want to have a separate instance, you want to CLONE your instance.
Create a Vector3D.Clone() method, which would look something like this:
public Vector3D Clone()
{
return new Vector3D(this.x, this.y, this.x);
}
Then your Main should look like this:
static void Main(string[] args)
{
Vector3D a, b;
a = new Vector3D(0, 5, 10);
b = new Vector3D(0, 0, 0);
b = a.Clone();
a.x = 10;
Console.WriteLine("vector a=" + a.ToString());
Console.WriteLine("vector b=" + b.ToString());
Console.ReadKey();
}
But as others have said, something as small as a Vector3D would be better suited as an immutable struct
You can make it a struct like Henk says. And you can add a constructor
struct Vector3D
{
public int x;
public int y;
public int z;
public Vector3D(int x, int y, int z)
{
this.x = x;
this.y = y;
this.z = z;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", x, y, z);
}
}
You could also do this without adding the constructor.
b = new Vector3D() {x=0, y=0, z=0};
No need to use a struct, I suggest you should design your Vector3D as an immutable class. Here are some good examples. Of course, a.x = 10 won't be possible for an immutable class.