C# Structs: Unassigned local variable? - c#

From the documentation:
Unlike classes, structs can be instantiated without using a new operator.
So why am I getting this error:
Use of unassigned local variable 'x'
When I try to do this?
Vec2 x;
x.X = det * (a22 * b.X - a12 * b.Y);
x.Y = det * (a11 * b.Y - a21 * b.X);
Where Vec2 x is a struct?

Well, are X and Y properties (rather than fields)? If so, that's the problem. Until all the fields within x are definitely assigned, you can't call any methods or properties.
For instance:
public struct Foo
{
public int x;
public int X { get { return x; } set { x = value; } }
}
class Program
{
static void Main(string[] args)
{
Foo a;
a.x = 10; // Valid
Foo b;
b.X = 10; // Invalid
}
}
Is Vec2 your own type? Do you have access to the fields involved, or only the properties?
If it's your own type, I would strongly urge you to try to stick to immutable structs. I know managed DirectX has some mutable structs for getting as close to optimal performance as possible, but that's at the cost of strange situations like this - and much worse, to be honest.
I would personally give the struct a constructor taking X and Y:
Vec2 x = new Vec2(det * (a22 * b.X - a12 * b.Y),
det * (a11 * b.Y - a21 * b.X));

It is still uninitialized. You need to initialize it before using it. You can use default operator for that if you don't want to create a static Vec.Empty value and happy with the defaults for the structs members:
Vec2 x = default(Vec2);
Mitch Wheat:
This, however doesn't:
public struct Vec2
{
int x;
int y;
public float X { get { return x; } set { x = value; } }
public float Y { get { return y; } set { y = value; } }
}
static void Main(string[] args)
{
Vec2 x;
x.X = 1;
x.Y = 2;
}
The compiler prevents you from calling propertis on types before all of it's members have been initialized, even though a property might just set one of the values. The solution, as Jon Skeet proposed, is to have an initializing constructor and preferably no setters.

Related

Value Tuple initialization is counter-intuitive

In the Sunday evening I have been watching some conferences this time I get hands on this one Conference Link
Where I found out pretty interesting think there is simple code example:
struct Point
{
private double x;
public double X { get => x; set => x = value; }
private double y;
public double Y { get => y; set => y = value; }
public Point(double x, double y) => (this.x, this.y) = (x, y);
public void SwapCode() => (X, Y) = (Y, X);
}
In Main:
var point = new Point(10.0, 11.0);
Console.WriteLine($"x: {point.X}, y: {point.Y}");
point.SwapCode();
Console.WriteLine($"x: {point.X}, y: {point.Y}");
And there is output of this :
x: 10, y: 11
x: 11, y: 10
So there is some questions:
How does it works ?
What I mean by that is Tuples should be translate into Tuple<T, K> which should be initialize with copy of the values but there it assign values to the variables at least for me it's kind of counter intuitive.
And i wonder if it's just sugar syntax think or there is happen some magic under this what make perfect sense but I can't spot it out?
Firstly structs should be immutable. Even though you can do this, you probably shouldn't.
Secondly, your SwapCode is actually doing this, as seen here.
public void SwapCode()
{
double num = Y;
double num2 = X;
double num4 = X = num;
num4 = (Y = num2);
}
Yeah, it's a little strange. However, it's just a little syntactic magic introduced in C#7. What it is actually doing is using a deconstruct method (the terminology .Net uses) to provide a set of out arguments for each of the params you want to extract. In this case, it's the properties/field you supplied!
To see it a little clearer, consider these two functionally equivalent code blocks
(int x, int y) asd = (1, 2); // create a Value Tuple
(int x, int y) = asd; // deconstruct it
(x, y) = (x, y); // assign to the deconstructed type
// All the above now has the swapped values
// they are all pointing to the same variables/memory
// You could even take this further by
x = 10;
y = 11;
// Once again, x and y, asd, and (x, y) all have the same values
// Because they are the same
// ----------------------------------------------------
int x = 1;
int y = 2;
(x, y) = (y, x); // we are just deconstructing our original variables
// All the above now has the swapped values
// they are all pointing to the same variables/memory
Note : As you can see, this is also a slightly more succinct way of swapping 2 variables as you don't have to use a temp variables, your friendly CLR does it for you
Anyway, you shouldn't be doing this with a struct anyway, they really should be immutable for various reasons

C# Complex Tanh fails for large values

This is the implementation from Microsoft for Sinh of a Complex
public static Complex Sinh(Complex value) /* Hyperbolic sin */
{
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Sinh(a) * Math.Cos(b), Math.Cosh(a) * Math.Sin(b));
}
and the implementation for Cosh
public static Complex Cos(Complex value) {
double a = value.m_real;
double b = value.m_imaginary;
return new Complex(Math.Cos(a) * Math.Cosh(b), - (Math.Sin(a) * Math.Sinh(b)));
}
and finally the the implementation for Tanh
public static Complex Tanh(Complex value) /* Hyperbolic tan */
{
return (Sinh(value) / Cosh(value));
}
Source: https://referencesource.microsoft.com/System.Numerics/a.html#e62f37ac1d0c67da
I don't understand why Microsoft implented the Tanh method that way?
It will fail for very large values. E.g.:
tanh(709 + 0i) --> 1, ok
tanh(711 + 0i) --> NaN, failed should be 1
Any ideas how to improve the tanh method that?
For double the Math.Tanh methods works for large values.
The complex tanh method could be implemented like that:
public static Complex Tanh(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tanh_a = Math.Tanh(a);
double tan_b = Math.Tan(b);
Complex num = new Complex(tanh_a, tan_b);
Complex den = new Complex(1, tanh_a * tan_b);
return num / den;
}
This will work as well for large values, see https://dotnetfiddle.net/xGWdQt.
Update
As well the complex tan method needs to be re-implemented that it works with larges values (imaginary part):
public static Complex Tan(Complex value)
{
double a = value.Real;
double b = value.Imaginary;
double tan_a = Math.Tan(a);
double tanh_b = Math.Tanh(b);
Complex num = new Complex(tan_a, tanh_b);
Complex den = new Complex(1, -tan_a * tanh_b);
return num / den;
}
See https://dotnetfiddle.net/dh6CSG.
Using the comment from Hans Passant another way to implement the tanh method would be:
public static Complex Tanh(Complex value)
{
if (Math.Abs(value.Real) > 20)
return new Complex(Math.Sign(value.Real), 0);
else
return Complex.Tanh(value);
}
See https://dotnetfiddle.net/QvUECX.
And the tan method:
public static Complex Tan(Complex value)
{
if (Math.Abs(value.Imaginary) > 20)
return new Complex(0, Math.Sign(value.Imaginary));
else
return Complex.Tan(value);
}
See https://dotnetfiddle.net/Xzclcu.

List.Find in Unity environment seems to depend on type casting

The setup for my List and the item class are as such:
public class mapVertex {
public Vector2 vertex;
public float x {
get{ return vertex.x; }
}
public float z {
get{ return vertex.y; }
}
public mapVertex(float x, float y) {
myID = ID++;
vertex.x = x;
vertex.y = y;
}
}
void Start() {
...
vertexList = new List<mapVertex>();
for (...)
vertexList.Add( new mapVertex( (float) 10.1, (float) 11.2 ) );
Following immediately in the code is the Find statement. After execution of the below however newEdge.B is equal to null.
for (...)
mapEdge newEdge = new mapEdge();
double[] vve = new double[2];
vve[0] = 10.1;
vve[1] = 11.2;
newEdge.B = vertexList.Find( x => (x.x == (float) vve[0]) && (x.z == (float) vve[1]) );
...
}
The below evaluates to true in the expression evaluator in MonoDevelop when I breakpoint on the line in question and the debugger confirms the values look correct, so I'm not sure why List.Find() isn't returning the first element of vertexList.
(vertexList[0].x == (float) vve[0]) && (vertexList[0].z == (float) vve[1])
Is this possibly related to a type conversion issue? The values of the items in vertexList were originally created by casting double to float (see above), but from what I understand doubles should be deterministic when casting to float.
Edit:
When changing
double[] vve = new double[2];
vve[0] = 10.1;
vve[1] = 11.2;
to
float[] vve = new float[2];
vve[0] = 10.1f;
vve[1] = 11.2f;
this seems to work..
Anyone know why?

Trying to remove ambiguous call in constructor involving int and long

"The call is ambiguous between the following methods or properties: 'fInt.fInt(int, bool)' and 'fInt.fInt(long, bool)'"
Here are my two constructors:
public fInt(int i, bool scale = true)
{
if (scale) value = i * SCALE;
else value = i;
}
public fInt(long i, bool scale = true)
{
if (scale)
{
if(i > long.MaxValue / SCALE || i < long.MinValue / SCALE)
Debug.LogError("fInt Overflow on creation with scaling");
value = i * SCALE;
}
else value = i;
}
Here's how I'm calling one with int using implicit conversion:
fInt i = 8;
I would like to be able to use both int and long so that I may avoid an extra check if it's not needed. Any thoughts on how to fix this? Would I simply have to do this:
fInt i = (int)8;
fInt i2 = (long)9;
I'd rather not have the extra typing if I can avoid it. Here are my implicit conversions:
//implicit int to fInt
public static implicit operator fInt(int i)
{
return new fInt(i);
}
//implicit long to fInt
public static implicit operator fInt(long i)
{
return new fInt(i);
}
It appears to be a bug in the Unity3D editor...as the code runs fine in Visual Studio. It only mixes up the signatures when the second parameter is optional.

Array and List discrepencies with structs

In the following code, a struct is obtained from an array and from a list. When getting the item by index, the array appears to do it by reference whereas the list appears to do it by value. Can someone explain the reasoning behind this?
struct FloatPoint {
public FloatPoint (float x, float y, float z) {
this.x = x;
this.y = y;
this.z = z;
}
public float x, y, z;
}
class Test {
public static int Main (string[] args) {
FloatPoint[] points1 = { new FloatPoint(1, 2, 3) };
var points2 = new System.Collections.Generic.List<FloatPoint>();
points2.Add(new FloatPoint(1, 2, 3));
points1[0].x = 0; // not an error
points2[0].x = 0; // compile error
return 0;
}
}
Changing the struct definition to a class makes both compile.
When you get a struct, it is always by value. The structure will be copied, you don't get a reference to it.
The difference is that you can access the sctruct directly in the array, but not in the list. When you change the property in the struct in the array, you access the property directly, but to do the same with a list you have to get the struct, set the property, then store the struct back in the list:
FloatPoint f = points2[0];
f.x = 0;
points2[0] = f;
Earlier versions of the compiler would let you write the code that you have, but for a list it would generate code similar to this:
FloatPoint f = points2[0];
f.x = 0;
I.e. it would read the struct, change it, and silently throw the changed struct away. The compiler was changed to give an error in that case.

Categories

Resources