I know structs are value types but then I do not understand why this works:
EDIT: I mean, why this.Size.Height does not work then?
struct A
{
int height;
public int Height
{
get
{
return height;
}
set
{
height = value;
}
}
}
//... class Main
{
A a = A();
a.Height = 5; //works. Why? I thought it should say "cannot modify as it is not variable". I think the properties should return copy of this struct...?
}
Second question - I have read I do not need to use "new" with structs but it does not work without it for me.
Let me break that down into several questions:
What is a variable?
A variable is a storage location that contains a value.
Why are value types called value types?
The value of a variable of value type is a value, and is copied by value. The value of a variable of reference type is a reference and is copied by reference. That is why value types are called value types and reference types are called reference types.
Why does a.Height = 10 work?
To change the value stored in a variable of reference type, you've got to have a variable to begin with. In this case, you do: you have the variable "a". The compiler compiles that as "pass the managed address of the variable 'a' to the Height setter with the argument 10". Therefore the Height property setter knows how to find the location of the value stored in 'a' and mutate it.
Why does a.Size.Height = 10 not work?
To change the value stored in a variable of reference type, you've got to have a variable to begin with. The expression "a.Size" is not a variable; it is a value. a.Size does not give you the variable that backs the property -- in fact, there might not be one. Instead, it gives you the value of the property. Value types are copied by value; this is a copy of the value of the property. This means that the compiler has two choices: it can copy the value into a temporary variable and then mutate that variable, tricking you into thinking that you've mutated the backing store of a.Size. Or, it can give you an error indicating that you're doing something foolish. It does the latter.
Isn't this confusing and vexing?
Yes. The moral of the story is do not make mutable value types. Only make immutable value types. Never have a setter on a value type in the first place; only do the assignment in the constructor. If the thing has to be mutable, make it a reference type.
Do I have to use "new" to make a new instance of a value type?
No. You can also use "default":
Foo f = default(Foo);
If Foo is a value type then this fills in the contents of storage location f with the Foo which has all its fields set to their default values.
Or, if the value type is mutable, you can simply set the values of all the fields. However, you have to set all of them if you do not use a constructor or the default initializer. You have to set all of them including private fields.
But if a struct has all public fields doesn't that violate best practices guidelines in two ways? First, because it has public fields, and second, because it is a mutable value type?
Yes. Don't do that.
I think you are confusing value types with immutability. I think this SO question will help you.
"this.Size.Height = 5" does not work because when a value type is used as the type of a property, the above line of code would actually mean "this.get_Size().set_Height(5)", and the result of the get_Size() call is a copy of the original, being a value type.
Thus, were it allowed by C#, setting the property value to 5 would change the copy's value rather than the original property value, which is highly undesirable.
Of course, this does not apply when the value type property of a class is changed via a local variable, so this scenario can be safely be supported.
It is very normal. And why you think that it must not let you to set value for Height ?
It is very normal behavior how properties should work.
Concerning calling new, yes it is not mandatory for value types. For value types it just calls default constructor which just initializes fields with default values.
A property will return the value that its "get" method returns. It's the same for structs and classes. If you provider a "set" method, it will do whatever the "set" indicates. The only way that Height could not be modified would be either to use a private "set", or not provide a "set" at all.
Related
I'm familiar with the C# specification, section 5.3 which says that a variable has to be assigned before use.
In C and unmanaged C++ this makes sense as the stack isn't cleared and the memory location used for a pointer could be anywhere (leading to a hard-to-track-down bug).
But I am under the impression that there are not truly "unassigned" values allowed by the runtime. In particular that a reference type that is not initialized will always have a null value, never the value left over from a previous invocation of the method or random value.
Is this correct, or have I been mistakenly assuming that a check for null is sufficient all these years? Can you have truly unintialized variables in C#, or does the CLR take care of this and there's always some value set?
I am under the impression that there are not truly "unassigned" values allowed by the runtime. In particular that a reference type that is not initialized will always have a null value, never the value left over from a previous invocation of the method or random value. Is this correct?
I note that no one has actually answered your question yet.
The answer to the question you actually asked is "sorta".
As others have noted, some variables (array elements, fields, and so on) are classified as being automatically "initially assigned" to their default value (which is null for reference types, zero for numeric types, false for bools, and the natural recursion for user-defined structs).
Some variables are not classified as initially assigned; local variables in particular are not initially assigned. They must be classified by the compiler as "definitely assigned" at all points where their values are used.
Your question then is actually "is a local variable that is classified as not definitely assigned actually initially assigned the same way that a field would be?" And the answer to that question is yes, in practice, the runtime initially assigns all locals.
This has several nice properties. First, you can observe them in the debugger to be in their default state before their first assignment. Second, there is no chance that the garbage collector will be tricked into dereferencing a bad pointer just because there was garbage left on the stack that is now being treated as a managed reference. And so on.
The runtime is permitted to leave the initial state of locals as whatever garbage happened to be there if it can do so safely. But as an implementation detail, it does not ever choose to do so. It zeros out the memory for a local variable aggressively.
The reason then for the rule that locals must be definitely assigned before they are used is not to prevent you from observing the garbage uninitialized state of the local. That is already unobservable because the CLR aggressively clears locals to their default values, the same as it does for fields and array elements. The reason this is illegal in C# is because using an unassigned local has high likelihood of being a bug. We simply make it illegal, and then the compiler prevents you from ever having such a bug.
As far as I'm aware, every type has a designated default value.
As per this document, fields of classes are assigned the default value.
http://msdn.microsoft.com/en-us/library/aa645756(v=vs.71).aspx
This document says that the following always have default values assigned automatically.
Static variables.
Instance variables of class instances.
Instance variables of initially assigned struct variables.
Array elements.
Value parameters.
Reference parameters.
Variables declared in a catch clause or a foreach statement.
http://msdn.microsoft.com/en-us/library/aa691173(v=vs.71).aspx
More information on the actual default values here:
Default values of C# types (C# reference)
It depends on where the variable is declared. Variables declared within a class are automatically initialized using the default value.
object o;
void Method()
{
if (o == null)
{
// This will execute
}
}
Variables declared within a method are not initialized, but when the variable is first used the compiler checks to make sure that it was initialized, so the code will not compile.
void Method()
{
object o;
if (o == null) // Compile error on this line
{
}
}
In particular that a reference type that is not initialized will always have a null value
I think you are mixing up local variables and member variables. Section 5.3 talks specifically about local variables. Unlike member variables that do get defaulted, local variables never default to the null value or anything else: they simply must be assigned before they are first read. Section 5.3 explains the rules that the compiler uses to determine if a local variable has been assigned or not.
There are 3 ways that a variable can be assigned an initial value:
By default -- this happens (for example) if you declare a class variable without assigning an initial value, so the initial value gets default(type) where type is whatever type you declare the variable to be.
With an initializer -- this happens when you declare a variable with an initial value, as in int i = 12;
Any point before its value is retrieved -- this happens (for example) if you have a local variable with no initial value. The compiler ensures that you have no reachable code paths that will read the value of the variable before it is assigned.
At no point will the compiler allow you to read the value of a variable that hasn't been initialized, so you never have to worry about what would happen if you tried.
All primitive data types have default values, so there isn't any need to worry about them.
All reference types are initialized to null values, so if you leave your reference types uninitialized and then call some method or property on that null ref type, you would get a runtime exception which would need to be handled gracefully.
Again, all Nullable types need to be checked for null or default value if they are not initialized as follows:
int? num = null;
if (num.HasValue == true)
{
System.Console.WriteLine("num = " + num.Value);
}
else
{
System.Console.WriteLine("num = Null");
}
//y is set to zero
int y = num.GetValueOrDefault();
// num.Value throws an InvalidOperationException if num.HasValue is false
try
{
y = num.Value;
}
catch (System.InvalidOperationException e)
{
System.Console.WriteLine(e.Message);
}
But, you will not get any compile error if you leave all your variables uninitialized as the compiler won't complain. It's only the run-time you need to worry about.
Quick question :
I am passing a class (reference type) to a method without using the "ref" keyword. Thus, the reference itself to my class is passed by value.
Then, I change the reference of my class (I make the reference point to another instance defined inside my method).
Finally, I return the initial method. However, in this case the returned instances points to the instance of the second class.
public Class Foo(Class A)
{
Class B = new Class();
A = B;
return A;
}
Foo returns a references pointing to B !
I am a little bit confused, since when doing A = B I make the reference of A point to another reference, or A's referenced is passed by value.
EDIT 1
Thanks for the response, but If I take the following example the change is not reflected. Indeed, I am trying to change the references of A but A's references is passed by value so in this case I understand why the change is not reflected..
void Foo(Class A)
{
A = null;
}
Many Thanks.
Basically, when you're passing an object, a reference is passed:
When an object of a reference type is passed to a method, a reference to the object is passed. That is, the method receives not the object itself but an argument that indicates the location of the object. If you change a member of the object by using this reference, the change is reflected in the argument in the calling method, even if you pass the object by value.
You can read more on this MSDN page.
You can read more on the other answers, but do notice that you're returning a class. Usually you'll return a specific object type, and when you won't be so free to do silly things like that. (of course, assuming that B inherits from A, you could create a new B inside the method and return it, which will be valid, but still, it's not making sense).
Another thing you might want to remember is the ref and out.
ref will expect an initialized value, and that value is changed in the method.
out doesn't care what it gets in, but you need to initialize and set it in the method.
Other than that, and the other answers here, either be more specific with your question and code, or have a read at the different links in the answers :)
You are passing a reference - an immutable value - into the method using the mutable variable, more precisely a parameter, A. Then you assign to the mutable variable A a new value, the immutable reference to the newly created object. Finally you are returning the current value of the variable A which at that point is the reference to the new object and no longer the reference to the object you passed into the method.
Essentially you are confusing the variable and the value stored in that variable. At no point did you change any reference, you only exchanged the value, i.e. reference, stored in the variable.
When you pass reference type by value the attempt to reassign the parameter to a different memory location only works inside the method and does not affect the original variable.
Check out Passing reference - type parameters .
I am using c#.
I have a method that outputs multiple values. I am aware of out but this is a reference type.
Is there anything equivalent to value type but that can also output multiple values from a method. With the reference type, the values are also changed outside of the method so I like to prevent.
out
I am aware of out but this is a reference type.
It's not clear what you mean. out isn't a type at all - it's a decorator for parameters. You can use it with reference types or value types:
// Nasty, but it does work...
void SplitInTwo(string input, out string x1, out string x2,
out int actualSplitCount)
{
string[] bits = input.Split('/');
x1 = bits[0];
x2 = bits[1];
actualSplitCount = bits.Length;
}
So you can use out either way. However, I would strongly advise you not to do so. You can use the Tuple family of types for ad hoc multiple values, but if the returned values are actually related, you should consider encapsulating them into a separate type, and returning a value of that type.
I'd recommend creating a class that describes your return value and has properties for each value you need to return.
Tuple is a decent option if you don't need to pass the result around often, but in general it's harder to maintain. I prefer working with meaningful property names rather than the Item1, Item2, Item3, etc. that Tuple provides. The out parameters also work, but they require the calling code to be written differently to accommodate the method implementation, which I recommend avoiding whenever possible.
Something along the lines of :
class MultiValue
{
type A {
get { return m_A; }
set { m_A = value; }
}
type B{
get { return m_B; }
set { m_B = value; }
}
private type m_A;
private type m_B;
}
Could work depending on what you're trying to do (Returns the value in a single instance or if you need to maintain those values over a period of time / methods).
But the Tuple types would also accomplish a similar effect, again, with better results depending what you want to do in your program.
The out keyword (and ref keyword) are used to indicate that a variable is provided from the caller's scope. They don't change the nature of the type in question.
out parameter modifier (C# Reference) # MSDN
If you're concerned requiring the caller being forced to specify out every time they use your method, you can use a Helper class or a Tuple to wrap the set of values returned.
Tuple Class # MSDN
You mention that you are concerned about reference-types being changed. This shouldn't be an issue to your method. The parameter specified by out is not shared by all cases where your method may used, they're local to the scope where your method is called. Only the caller needs to worry, and only in their own scope.
Last, if you want to indicate that a variable may be altered or used without being required to assign a value to it as out requires, use ref.
For C# in VS2005, what will be value of variables of the following types if they are simply declared and not assigned to any value? ie. What are their default values?
int
bool
string
char
enum
Here's what default value for each type you've mentioned would be.
int = 0
bool = false
string = null
char = '\0'
enum = 0 //behind the scenes enum is int
Taking this forward, at runtime if you wish to capture default value of any type then you can use default statement in C# and simply call it as following.
//This will print 0 on screen.
Console.WriteLine(default(int));
Generally, this is used in generics for identifying default values of generic type arguments, where the type is only known at runtime.
If they're used locally (i.e. they're not members of a class or struct) they won't have default values. You won't be able to use them until they're assigned a value (unless you explicitly "new them up").
If they're not used locally, they'll default to 0, false, null, and '\0'.
Edit: You've added enum to your list. enums default to a value of 0 because they use an int by default behind the scenes. So whatever enumerate is declared as 0 for the enum (typically the first enumerate, but that's overridable) will be the default. If you don't have a 0 value enumerate for whatever reason, then you'll have an invalid value for your enum as the default value.
Please explain. I am talking about declaring the variables inside the scope of a class or method. – Craig Johnston
I told a little white lie to point out how the compiler works. If you declare a local variable, the compiler will not compile if you try to use it without having first explicitly assigning a value to that variable; that includes null for reference types.
For example:
public void Foo()
{
int bar;
int barPlus5 = bar + 5; // Compiler Error!
}
Technically, bar still has a default value of 0, but because the C# compiler will not allow you to use that default value in a locally scoped variable, a locally scoped variable effectively doesn't have a default value. <Ben Kenobi>So what I told you was true, from a certain point of view.</Ben Kenobi>.
There are exceptions to the rule: out parameters get a pass because the compiler enforces that an out parameter must be assigned by a method before it returns, and you can do int bar = new int(); to get the default value, since that's technically an assignment.
Now, if you declare a variable as a member of a class or a struct such as follows:
public class Foo
{
public int Bar {get;set;}
public Foo() { }
}
And then you instantiate Foo somewhere, Bar will have a default value of 0.
For example:
var foo = new Foo();
Console.WriteLine(foo.Bar); // output: 0
MSDN article - Value Types.
All value types implicitly declare a
public parameterless instance
constructor called the "default
constructor". The default constructor
returns a zero-initialized instance
know as the default value for the
value type.
In case of local variables (Value or
Reference Types) in C#, they must be
initialized before they are used.
MSDN Article - Types
A type that is defined as a class,
delegate, array, or interface is a
reference type. At run time, when you
declare a variable of a reference
type, the variable contains the value
null until you explicitly create an
instance of the object by using the
new operator, or assign it an object
that has been created elsewhere by
using new.
1) Why must initialization value of field members be determinable at compile time?
2) But if the initialization value needs to be determined at compile time, then why am I able to initialize a A.b field using a reference to an object:
class A
{
B b = new B();
}
class B {}
Thank you
I'm a bit confused; there is no such rule for fields. In particular, fields are explicitly initialized anyway - either by your code, or to the type's default. The only corner-case is explit struct field initialization, in which all fields must be assigned before the struct is considered complete.
I wonder if you are talking about "definite assignment" of variables within methods; i.e.
void Foo() {
int i;
Console.WriteLine(i); // not valid; i not assigned
i = 1;
Console.WriteLine(i); // would be value
}
This is so that for method variables the values never suffer from random values picked up from the stack. Actually, there is an IL marked that means that locals are wiped - and IIRC the C# compiler includes this marker anyway... but the language spec says method variables must be definitely assigned.
In the case of you example, that field-initialization essentially becomes part of the common constructor code. But you'd never notice it.
1) Why must initialization value of field members be determinable at compile time?
It mustn't. Why do you think that ?
If you mean this part of the book Illustrated C# 2008, then it is in the section talking about const fields. The compiler may replace the use of a const field with the value of the const field, so the initialiser for the field must be constant.
The field in your original post is not a const. Therefore the restriction does not apply to it.