While learning C#, this question came to my mind. What is the difference between void and var?
Here are the two example I would like to share:
void * voidInt = (void *) 7;
void * voidChar = (void *) 'F';
void * voidCharArray = (void *) "AbcString";
And this is example of var:
var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
Is void an anonymous datatype?
If yes, then what is the major
difference between var and void?
Can someone help me clear this situation?
The other answers here are pretty good but I think they do not get clearly to the fundamentals. It is the fundamentals you are confused about, so let's address those.
A variable is a storage location that contains a value.
A variable is associated with a type.
A local variable has a name.
So voidInt, voidChar, voidCharArray, varInt, varChar and varCharArray are all variables, and they all have types associated with them. Each variable can be assigned a value of that type or produce a value of that type, depending on whether the variable is being written to or read from.
OK, so now what are pointers?
A type has a corresponding pointer type. (Note that in unsafe C# only the unmanaged types have corresponding pointer types.)
The void * type is a special pointer type.
A pointer is a value.
A pointer of type T* may be dereferenced to produce a variable of type T. T* must not be void*.
A pointer may be explicitly converted to or from any integral type, though these operations are permitted to lose information and are dependent on implementation details.
Any pointer value may be implicitly converted to void*.
Any void* value may be explicitly converted to any pointer type value.
And what is var in C#?
var is a "syntactic sugar" that tells the compiler to deduce the type of the variable from the initialzier rather than requiring that it be written out.
And what are "anonymous types" in C#?
Some expressions in C# have a type that is not declared and has no name; these are known as the "anonymous" types.
So now we can look at your program and see what each line does.
void * voidInt = (void *) 7;
voidInt is a variable of type void*. The value assigned to it is the conversion of the integer 7 to a pointer, which is almost certainly a garbage pointer on any modern operating system. This code is essentially nonsensical.
More sensible code would be:
int myInt = 7;
int* intPtr = &myInt;
void* voidInt = intPtr;
This means that myInt is a variable which holds the value 7, intPtr is a variable which holds a pointer; when that pointer is dereferenced it produces variable myInt. voidInt is a variable which holds any pointer, and the value read from intPtr is a pointer. So now voidInt and intPtr both hold a pointer to variable myInt.
void * voidChar = (void *) 'F';
Same thing here. The character F is treated as a number and converted to a pointer value, which is stored in the variable. This is not sensible. Sensible code would be something like:
char myChar = 'F';
void *voidChar = &myChar;
But this makes perfect sense:
void * voidCharArray = (void *) "AbcString";
A string literal in C++ is convertible to a char* which is a pointer to the storage for the first character, and that pointer is convertible to void*.
What about this?
var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
This is just a pleasant way to write
int varInt = 7;
char varChar = 'F';
string varCharArray = "AbcString";
Each variable has its given type, and each assignment stores a value of that type in the variable.
What about anonymous types?
var anon = new { X = 123, Y = 456 };
This makes a variable of anonymous type, where the anonymous type has two properties X and Y both of type int. The type has no name, so there is no way to write out the type in the declaration, hence var must be used.
The key thing here is to make sure that you have a grasp of the fundamentals: pointers are values, they may be dereferenced, and doing so produces a variable. Since pointers are values they may themselves be stored in variables of pointer type. This has almost nothing to do with var, which is a pleasant way in C# to make the compiler do the work of figuring out what type a variable should have.
void and var do not really have anything in common:
void (as used by pointer variables in C and C++) means an unspecified (not a definite) type. void* aren't permitted* in managed C# (although a very weak type, such as an object reference might be a close approximation). Generally, void* types need to be re-cast in order to be useful.
However void return types from a method / function mean the same
in both languages, which is to convey that there is no return value (like Unit in Scala)
In contrast, var in C# defines an implicitly typed variable - the variable still has a strong type, but the actual type is inferred from the right hand side at compile time.
e.g.
var v1 = "Foo"; // v1 is a string, because it is inferred from the right hand side
var v2 = XDocument.Parse(#"c:\temp\foo.xml"); // v2 is the return type of the function
var is often required when using anonymous types - this is probably where you've made the connection between var and anonymous types:
var v3 = new { Name = "Foo", Value = 123}; // v3 is strongly typed, anonymous class.
var is especially useful for assigning variables to the return values of LINQ expressions, where the types can be quite complex:
var v3 = db.Persons
.Join(db.Cities, p => p.CityId, c => c.Id, (p, c) => new {Person = p, City = c})
.GroupBy(pc => pc.City.Name);
* Actually, that's not entirely true, you can use void* in C# with unsafe
Edit
One further thing worth mentioning, that as of C#6, that implicit var typing can only be used for local variables, i.e. C# doesn't support implicit typing of method return types (unlike functional languages like Scala, where the compiler in most instances can also infer the return type of a method).
In an unsafe context, the equivalent of C++ void* in C# is void*. Any data pointer type can be assigned to a void*.
In a safe context, object is (loosely) the corresponding concept. Any class/interface/struct instance can be assigned to it.
The equivalent of C# var in C++ is auto. When used to declare and initialize a local variable, it acts as the type of the expression assigned to that variable, if that is possible.
You can do this with c++ void pointer:
void * val = (void *) 7;
val = (void *) "Abcd";
But you cannot do this with c# var:
var val = 7;
val = "abcd";
This will throw an error.
Update
If you want to achieve similar behavior of void * you can use dynamic.
dynamic val = (dynamic) 7;
val = (dynamic) "ABC";
When var is used, the actual type of the variable is determined at compile time. But, when dynamic is used, the actual type of the variable is determined at run time.
Related
I have an unmanaged code which is a type of:
unsigned long *inputParameters
I need to convert my variable inputparameters to C# type
ulong[] inputParameters
I've tried different types of conversions like
auto inputParams = *((unsigned long*)inputParameters)
&inputParameters
however I am getting this exception:
cannot convert argument from 'unsigned long *' to 'cli::array<unsigned __int64,1> ^'
Any types known in C# as reference types, need to be instantiated by using the gcnew keyword, arrays being no exception. Most value types are marashalled behind the scenes, so you can generally just assign managed to unmanged and vice versa without any casting or trickery. Magic, I know! There are some exception, but the compiler will let you know if there is an issue.
I am assuming that *inputParameters is a pointer list (rather than a pointer to a single value), which means that you should have a variable that contains the number of elements in the list, lets call it nElements. To do the conversion, you can do the following:
//some test data
int nElements = 10;
unsigned long *inputParameters = (unsigned long *)malloc(sizeof(unsigned long) * nElements);
for (int i = 0; i < nElements; i++)
{
*(inputParameters + i) = i * 2;//just arbitrary values
}
//now create a .NET array (lines below directly solve your question)
array<UInt64, 1>^ managedArray = gcnew array<UInt64, 1>(nElements);
for (int i = 0; i < nElements; i++)
{
tempArray[i] = *(inputParameters + i);//this will be marshalled under the hood correctly.
}
//now the array is ready to be consumed by C# code.
Here, array<UInt64, 1>^ is the C++/CLI equivalent of C#'s ulong[]. You can return managedArray to a method call from C# that expects ulong[] as the return type.
struct Point
{
public int x;
public int y;
}
void Main()
{
Point p;
p.x = 1;
p.y = 1;
Object o = p;
((Point) o).x = 4; // error
((Point) o).x = 5; // error
((Point) o).x = 6; // error
p = (Point) o // expect 6
}
Why doesn't it compile to
ldloc.1 // o
unbox Point
ldc.i4.4
stfld Point.x
Where C++ CLI allows it.
For those who don't know, unbox is not required to create a copy of value types, instead it pushes a pointer to the value on to the stack.
Only assignment would create a copy.
Because of how value types work, the boxed Point is a copy of the original, and "unboxing" it by casting back to Point creates yet another copy. From the C# language spec (§1.3, "Types and Variables"):
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.
Modifying the copy wouldn't change the original anyway, so it wouldn't make much sense to allow it.
As for C++...well...of course, the rules of C# don't necessarily apply to it. :) The CLR actually has quite a bit more flexibility with pointers and references than you'd first think, and C++ -- being known for such flexibility -- probably takes advantage of it.
You can't do this, because the result of unboxing is a copy of the boxed value, not the boxed value itself. And casting object to a value type is the definition of unboxing. So, if the compiler allowed you to do this, it would be very confusing, because the assignments wouldn't actually do anything.
I think the reason your code works in C++/CLI is because that language in general has more support for working (or not) with references, including strongly-typed boxes (e.g. Point^) and treating (some) classes as value types (e.g. using MemoryStream without ^).
You can accomplish this using the System.Runtime.CompilerService.Unsafe.Unbox function:
static void Main()
{
Point p;
p.x = 1;
p.y = 1;
Object o = p;
Unsafe.Unbox<Point>(o).x = 6; // error
p = (Point)o; // 6
Console.WriteLine(p.x);
}
As the documentation notes, and I presume the reason it is considered unsafe, is that you must not do this with an immutable built-in type [e.g. Unbox<int>(i) = 42], and the system does nothing to enforce this.
When declaring an int..
int A = 10;
why not do the following instead?
int A = new Int()
A=10;
are both the same?
Because int is syntax sugar for Int32 which is a value type. Incidentally, so is the constant value 10 (an instance of the value type Int32). That's why you don't need to use new to create a new instance, but rather making a copy of 10 and calling it A. And similar syntax works with reference types as well, but with the difference that a copy isn't made; a reference is created.
Essentially, you can think of 10 as a previously declared instance of Int32. Then int A = 10 is just setting variable A to a copy of value 10 (if we were talking about reference types then A would be set to a reference to the instance instead of a copy).
To better illustrate here's another example:
struct SomeValueType {
public SomeValueType(){
}
}
public static readonly SomeValueType DEFAULT = new SomeValueType();
Then you can just do this:
SomeValueType myValueType = DEFAULT; // no neeed to use new!
Now imagine that SomeValueType is Int32 and DEFAULT is 10. There it is!
You may have seen Java, where int and Integer are two different things, and the latter requires you to write new Integer(10).
In C# int is a special alias for Int32, and for all intents and purposes they are the same. Indeed, to create a new instance of any type you'd have to write new Int32() or something.
However, because integers are primitive types in C# (and most programming languages), there is a special syntax for integer literals. Just writing 10 makes it an Int32 (or int).
In your example you are actually assigning a value to the a variable twice:
int a = new Int32(); // First assignment, a equals 0
a = 10; // Second assignment, a equals 10
You might imagine that since the second assignment overwrites the first, the first assignment is not required.
In C# there are two kinds of types, "reference types" and "value types". (Pointers are a third kind of type but let's not get into that.)
When you use the default constructor of a value type, all you are saying is "give me the default value of this value type". So new int() is neither more nor less than just saying 0.
So your program is the same as:
int i = 0;
i = 10;
if you write youe code like
int A = new Int();
the variable 'A' is assigned by the default value of int, so you can use variable 'A' without assigning a value to it(in c# we cant use a variable without assigning a value to it)
when using the keyword new it will automatically call the default constructor, it will assign default values to the variables.
int A = new Int();
It declares and initializes A to 0.
Basically, the new operator here is used to invoke the default constructor for value types. For the type int, the default value is 0.
It has the same effect as the following:
int A = 0;
I have a following function which accepts a enum value and based upon the enum value returns a constant value(which is in a different class). Now i get a "Constant initializer missing" Error.
public const int Testfunction(TESTENUM TestEnum)
{
switch(TestEnum)
{
case TestEnum.testval1:
return testclass.constvalue;
case TestEnum.testVal2:
return testclass.constvalue1;
case TestEnum.testVal3:
return testclass.constvalue2;
}
}
how exactly the function's return type would be? (I am using object return type and this does not throw any error)
Is there any other option to achieve the same?
What's happening here is the compiler thinks that you are trying to declare a public constant integer field named Testfunction, and is extremely surprised to discover that there is no = 123; following the identifier. It's telling you that it expected the initializer.
There are a number of places in the C# compiler where the development team anticipated that C and C++ users would use a common C/C++ syntax erroneously. For example, there's a special error message for int x[]; that points out that you probably meant int[] x;. This is an example of another place where the compiler could benefit from a special-purpose error message that detects the common mistake and describes how to fix it. You might consider requesting that feature if you think it's a good one.
More generally, "const" in C# means something different than it means in C or C++. C# does not have the notion of a "const function" that does not mutate state, or a "const reference" that provides a read-only view of potentially-mutable data. In C# "const" is only used to declare that a field (or local) is to be treated as a compile-time constant. (And "readonly" is used to declare that a field is to be written only in the constructor, which is also quite useful.)
Removing "const" keyword from your function return type should solve the problem
It should be like this
public int Testfunction(TESTENUM TestEnum)
{
...
Return type cannot be declared constant
.NET methods cannot return const any type..
The const keyword is invalid there: remove it.
The most likely working code:
public static class TestClass
{
public const int constValue1 = 1;
public const int constValue2 = 2;
public const int constValue3 = 3;
}
enum TestEnum
{
testVal1, testVal2, testVal3
}
public int TestFunction(TestEnum testEnum)
{
switch (testEnum)
{
case TestEnum.testVal1:
return TestClass.constValue1;
case TestEnum.testVal2:
return TestClass.constValue2;
case TestEnum.testVal3:
return TestClass.constValue3;
}
return 0; // all code paths have to return a value
}
First, according to const (C# Reference):
The const keyword is used to modify a declaration of a field or local variable. It specifies that the value of the field or the local variable is constant, which means it cannot be modified.
In C#, const is only used as a modifier of a field (like TestClass.constValue1) or local variable, not suitable for a function return type.
So you are from the great C/C++ kingdom. Thinking with my very limited knowledge to C/C++, const return types in C/C++ is only meaningful with pointers...
// C++ code
const int m = 1;
// It returns a pointer to a read-only memory
const int* a(){
return &m;
}
But unless you are using unsafe code, there is no pointer in C#. There are only value types (like int/DateTime/TestEnum/structs) and reference types (like string/classes). There are a lot more to read about on the web.
So as int is a value type in C#, when you returns it, it gets copied. So even if you are returning a "constant int" the returned value is not a constant and modifying the return value will not "change the constant and cause a SegFault".
Well, I forgot to answer your questions...
How exactly the function's return type would be? (I am using object return type and this does not throw any error)
Like what I showed in the code above, int.
const int blah = 1 only declares a variable/field blah of type int which one must not modify it (by doing blah = 2). In C# const int is not a type.
Is there any other option to achieve the same?
Well... I think I don't actually need to answer this...
One of the libraries I'm using defines this in C#:
public ushort GetParameterSet(string name, out ParameterSet parameterSet)
I'm trying to call this from F#:
let parameterSet = new ParameterSet();
let retVal = currentPanel.GetParameterSet(name, ref parameterSet);
However, even though the parameterSet is set to an instance of that
class with valid data in the C# method, it does not change in F#.
What am I missing here?
First of all, why your code doesn't work as is: ref doesn't have the same meaning in F# as it does in C#. In F#, 'a ref is a type. It's not magical, either - it's really just a record with a single field contents, defined as follows:
type 'a ref = { mutable contents : 'a }
It is not a pointer or reference to a local variable. Thus, when you write this:
let x = 0
let y = ref x
you do not have variable y referencing x. Instead, you have variable y of type int ref, with the value of contents initialized to the value that x had (that is 0). You can change that:
y.contents <- 1
and this will not change the value of x. It will only change the value of contents
F# also provides some syntactic sugar for 'a ref. Specifically, this:
y.contents <- y.contents + 1
can be written shorter as:
y := !y + 1
Thus := is a shorthand for assigning to contents, and ! is a shorthand for reading its value.
See Reference Cells in MSDN for more information on ref.
Now F# has a magic cast associated with 'a ref type, that lets you pass an instance of that type to a foreign function that expects a byref argument (both ref and out in C# map to byref in IL). In this case, if function changes the value of the argument, the value of contents in your ref instance changes accordingly. In your example, ref parameterSet created a new instance of ref, passed it to function which changed it, and then discarded it. What you should have done is this:
let parameterSet = ref(new ParameterSet())
let retVal = currentPanel.GetParameterSet(name, parameterSet)
...
// use parameterSet.contents as needed
Alternatively, you could use let mutable to declare a mutable local variable, and then use the magical & operator to pass it to the function directly as byref:
let mutable parameterSet = new ParameterSet()
let retVal = currentPanel.GetParameterSet(name, ¶meterSet)
Try
// let parameterSet = null;
let retval, parameterSet = currentPanel.GetParamterSet(name);
You shouldn't pass an instance as ref parameter, when the method expects an out parameter (which upon calling should be an unassigned reference preceded by the out keyword).