45

I've recently tried to create a property for a Vector2 field, just to realize that it doesn't work as intended.

public Vector2 Position { get; set; }

this prevents me from changing the values of its members (X & Y)

Looking up information on this, I read that creating a property to a Vector2 struct returns only a copy of the original object and not a reference.

As a Java developer this confuses me.

When are objects in C# passed by value and when are they passed by reference?
Are all struct objects passed by value?

svick
  • 236,525
  • 50
  • 385
  • 514
Acidic
  • 6,154
  • 12
  • 46
  • 80
  • 1
    You need to show more. This should work as you expect it to. – Captain Giraffe Feb 12 '12 at 18:53
  • 5
    a `struct` is a value type - so it is passed by value - for each reference type on the other hand (i.e. class) by default a copy of the reference is passed (the reference itself is passed by value) – BrokenGlass Feb 12 '12 at 18:54
  • 5
    @b1naryj the stack vs heap part is an implementation detail that is almost always an unhelpful way of thinking about it. – phoog Feb 12 '12 at 19:05
  • 1
    @b1naryj Nobody misses that because it doesn’t exist: `class Foo { Vector2 x; }` – now the struct value `x` is allocated on the heap, not on the stack. – Konrad Rudolph Feb 12 '12 at 19:08
  • 10
    Structs are passed by value. As you have discovered, making a mutable struct is a "worst practice" because doing so is so confusing. Make structs immutable values, just like integers are immutable values. – Eric Lippert Feb 12 '12 at 19:50
  • @EricLippert Structs are passed by value in the same way references are passed by value, it's the default for parameter passing in C#, not because it's a value/reference type. There's a difference between *passing* by value/reference & value/reference *types* (which is the point I feel you are glazing over too casually). This is not the case when using `ref`/`out`, as you are passing by reference at this point as [Konrad mentions](http://stackoverflow.com/a/9251645/50776) (& Jon skeet has *many* times, hence his [blog post](http://www.yoda.arachsys.com/csharp/parameters.html) on the matter). – casperOne Feb 13 '12 at 19:41

9 Answers9

98

It is important to realise that everything in C# is passed by value, unless you specify ref or out in the signature.

What makes value types (and hence structs) different from reference types is that a value type is accessed directly, while a reference type is accessed via its reference. If you pass a reference type into a method, its reference, not the value itself, is passed by value.

To illustrate, imagine we have a class PointClass and a struct PointStruct, defined analogously (omitting irrelevant details):

struct PointStruct { public int x, y; }

class PointClass { public int x, y; }

And we have a method SomeMethod that takes these two types by value:

static void ExampleMethod(PointClass apc, PointStruct aps) { … }

If we now create two objects and call the method:

var pc = new PointClass(1, 1);
var ps = new PointStruct(1, 1);

ExampleMethod(pc, ps);

… we can visualise this with the following diagram:

diagram

Since pc is a reference, it doesn’t contain the value in itself; rather, it references an (unnamed) value somewhere else in memory. This is visualised by the dashed border and the arrow.

But: for both pc and ps, the actual variable is copied when calling the method.

What happens if ExampleMethod reassigns the argument variables internally? Let’s check:

static void ExampleMethod(PointClass apc, PointStruct aps); {
    apc = new PointClass(2, 2);
    aps = new PointStruct(2, 2);
}

Output of pc and ps after calling the method:

pc: {x: 1, y: 1}
ps: {x: 1, y: 1}

→ ExampleMethod changed a copy of the values, and the original values are unaffected.

This, fundamentally, is what “pass by value” means.

There’s still a difference between reference and value types, and that comes into play when modifying members of the value, not the variable itself. This is the part that trips people up when they are confronted with the fact that reference types are passed by value. Consider a different ExampleMethod.

static void ExampleMethod(PointClass apc, PointStruct aps) {
    apc.x = 2;
    aps.x = 2;
}

Now we observe the following result after calling the method:

pc: {x: 2, y: 1}
ps: {x: 1, y: 1}

→ The reference object was changed, whereas the value object wasn’t. The diagram above shows why that is: for the reference object, even though pc was copied, the actual value that both pc and apc reference remains identical, and we can modify that via apc. As for ps, we copied the actual value itself into aps; the original value cannot be touched by ExampleMethod.

Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • 15
    While this is (technically) correct, I feel that it's a confusing answer. C# (and .NET in general) chose the Value Type vs. Reference Type abstraction. Deconstructing that abstraction might be technically true, but in practice it's not productive. – Avner Shahar-Kashtan Feb 12 '12 at 18:59
  • 42
    @Avner Sorry but you are incorrect. The distinction is *crucial* because otherwise you end up with a flawed understanding and faulty code. If you though that references were passed by reference (and many programmers do!) you will expect that modifications to the reference in the method are visible to the caller (and again, many programmers do expect that). So my answer isn’t only technically true, it’s of practical relevance (and thus productive). Paraphrasing Feynman: if reality is too confusing for you, that’s just too bad, choose a different reality. – Konrad Rudolph Feb 12 '12 at 19:04
  • 5
    @Konrad: I tend to agree with Avner. Yes, as you delve deeper into understanding the language, it can become useful to know that you are always passing values to methods. But, in general, the *value* is not considered to be the reference itself. For example, if I have `string s = "abc";`, most people would consider "abc" to be the *value*. And, in this case, it can be helpful to think of the argument as being passed by reference. – Jonathan Wood Feb 12 '12 at 19:33
  • 1
    If a parameter of a reference type is passed by reference, then assigning a new object to the parameter variable will alter the original variable of the caller. If, however, it is passed by value, this will not affect the original value. It is very important to makes this distinction. Reference types and value types can both be passed by reference or by value. – Olivier Jacot-Descombes Feb 12 '12 at 20:15
  • 2
    @Konrad: It seems like a semantic difference to me. Ask anyone what the value of a string is and they'll say it's the text the variable references. So saying the string is passed by reference can also be correct. Indeed, it is the terminology [Microsoft uses](http://msdn.microsoft.com/en-us/library/0f66670z(v=vs.100).aspx). Perhaps I missed it, but I'm having a hard time thinking of examples where your distinction is helpful to regular developers. – Jonathan Wood Feb 12 '12 at 20:41
  • 8
    @Jonathan Just as an aside, [Microsoft *sucks* at terminology](http://stackoverflow.com/questions/9251608/are-structs-pass-by-value/9251645#comment11658479_9251636). Ignore them, they are huge trolls. As for an example where the distinction matters, there are enough [questions](http://stackoverflow.com/q/6070892/1968) on [SO](http://stackoverflow.com/q/498747/1968) where this tripped somebody up. It should be easy to see that the distinction *is* helpful. – Konrad Rudolph Feb 12 '12 at 21:04
  • 7
    @JonathanWood: The value of a string object is of course the text, but the value of a string *variable* is the reference to the string object. The term *passing by reference* is when you use the `ref` keyword, and it's only confusiong if you use it when you actually mean passing *a* reference. – Guffa Feb 13 '12 at 07:29
  • 2
    @JonathanWood to add to Guffa's comment: If `M(myString);` is passing by reference, how do you explain `M(ref myString);` or `M(out myString);`? It seems much more useful to say that a reference type is an object that may only be accessed by way of a reference. Confusion arises when we shortcut that by saying, e.g., that `string.Substring` returns a new string. It doesn't. It returns *a reference to* a new string. When simplified terminology leads to confusion, it's better to stop over-simplifying rather than to extend the simplification into more confusing territory like param modifiers. – phoog Feb 13 '12 at 16:28
  • Obligatory [reference to Jon Skeet blog post on the topic](http://www.yoda.arachsys.com/csharp/parameters.html) – casperOne Feb 13 '12 at 19:47
  • –1 for making saying everything is pass by reference in your first statement in bold, then burying the heart of the matter that for classes it is the const reference that is passed at the end of your answer. Order matters, if you invert your answer people get what they actually need. – Chris Marisic Mar 25 '15 at 14:50
  • @ChrisMarisic I can't help that, you're simply wrong. C# is pass by value. Deal with it. That **is** the heart of the matter. – Konrad Rudolph Mar 25 '15 at 14:52
  • 1
    @KonradRudolph being pedantically correct doesn't mean it's actually useful. And great retaliatory downvote ;) – Chris Marisic Mar 25 '15 at 15:38
  • @ChrisMarisic I don’t retaliate with downvotes. And you misunderstand what this answer entails. It is emphatically not about pedantism, as I’ve explained in a previous comment (with, currently, 22 upvotes), it’s about actually understanding C#’s object model. Saying anything other than that C# passes by value (a) spreads a fundamental misunderstanding of the object model, and (b) leads people to have false expectations about their code’s semantics, which makes it buggy. – Konrad Rudolph Mar 25 '15 at 16:20
  • @ChrisMarisic You’re saying that being able to reason correctly about semantics and having an accurate understanding of the type system is pedantic? Houston, we have a problem. – Konrad Rudolph Mar 25 '15 at 16:47
  • The pedantics are choosing to use words that are purely ambiguous in their context. If there was no ambiguity none of these threads would exist. My answer removes all ambiguity whereas your answer drastically increases the ambiguity due to its paragraph structure. I mean how more ambiguous can you make a sentence that starts with **EVERYTHING*** (asterisk terms and conditions apply) then further reframe the emboldened proclamation. – Chris Marisic Mar 25 '15 at 16:57
  • @Chris Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/73796/discussion-between-konrad-rudolph-and-chris-marisic). – Konrad Rudolph Mar 25 '15 at 17:12
  • This answer is definitely confusing. It infers that reference type objects need to be passed with a `ref` or `out` param when that's just not the case. Non-reference types do need this. Simple as that. Even if the reference is being passed by value, it doesn't matter, you are just passing around a 'reference value" at that point, and one could argue either way that it's still being passed by reference. This answer is so grey I've gone color blind. Instead of answering the question directly you have now confused everyone here. – ganjeii Jul 18 '17 at 17:36
  • @ganjeii No, you're simply completely wrong, end of discussion. Read the comments: This has been chewed up again and again *ad nauseam*. – Konrad Rudolph Jul 18 '17 at 18:33
  • 1
    I need come to Konrad's defense here since his answer is as clear and correct as the detractors are misguided. Like just about anything, you can't use value types properly without understanding their [*semantics*](http://en.wikipedia.org/?curid=397608), and unlike @JonathanWood, I [mean that word correctly](http://english.stackexchange.com/q/97318) (see also [here](http://english.stackexchange.com/q/339082)) here--i.e., not that the differences are 'unimportant' but rather that they are precisely meaningful and knowable... – Glenn Slayden Nov 25 '17 at 03:36
  • 1
    ...Even cars, often mis-cited as something you don't need to understand to use, require specific technical knowledge to operate, and we call safe drivers 'responsible' rather than denouncing them as 'pedantic'. If one considers the well-established behavior of `.NET` value types too be too complex, it's a simple choice to not use them. IMHO that's the only tenable argument here. – Glenn Slayden Nov 25 '17 at 03:36
  • The 1st statement is wrong. Value types are passed by value and reference types are passed by reference. – sergiol May 29 '18 at 17:12
  • @sergiol No. Sorry. You’re unambiguously wrong and, what’s more, this misunderstanding has been repeatedly brought up as you can read in the comments — there’s no need to bring it up yet again! Anyway, this isn’t up for debate. C# (and most similar languages) are pass-by-value, as this answer explains in great detail. – Konrad Rudolph May 29 '18 at 17:18
  • 2
    After coming back to this post time and time again, I have to give it this to @KonradRudolph. My apologies on my previous comment above. I've gained what I would hope to consider quite a bit of beneficial knowledge int he last few years lol, and can finally comprehend clearly what you are saying. This is actually a well formed explanation, I doubt many others would be able to explain it in a more comprehensible way. Nice work. Sucks that you got so much flak for this. Apologies once more for my ignorance. God speed good sir. – ganjeii Mar 08 '20 at 05:42
  • The pratical effects of the difference are very important to be known, no matter the words or semantical words used. Another important thing to note is that you cannot change internal values of structs inside lists (instead you must create a new-changed instance if the item and replace it). Classes,instead, can be changed in loco. – Zuabros Sep 25 '20 at 04:43
  • @KonradRudolph You've defeated your own argument - you said "references were passed by reference" when you meant "references were passed by reference by value", which according to you is a crucial distinction. – Fax Jun 23 '22 at 10:32
  • @Fax No. I didn’t say that. I said that *if somebody thinks that*, then they’re mistaken. – Konrad Rudolph Jun 23 '22 at 11:44
  • @KonradRudolph I know, I'm saying _your description_ of what people think is ambiguous according to your own definition of "by reference". – Fax Jun 23 '22 at 12:33
  • @Fax I am merely repeating/paraphrasing a common misconception, in order to address it. I really don’t understand your issue with this. – Konrad Rudolph Jun 23 '22 at 12:52
25

A struct is a value type, so it's always passed as a value.

A value can either be a reference type (object) or a value type (struct). What's passed around is always a value; for a reference type you pass the value of the reference to it, for a value type you pass the value itself.

The term by reference is used when you use the ref or out keywords to pass a parameter. Then you are passing a reference to the variable that contains the value instead of passing the value. Normally a parameter is always passed by value.

Guffa
  • 687,336
  • 108
  • 737
  • 1,005
  • So, there is no easy way to implement properties with a struct? – Acidic Feb 12 '12 at 19:11
  • @Acidic: Yes. If you need to set the properties individually of a struct property, then it should most likely not be a struct anyway. – Guffa Feb 12 '12 at 20:10
  • @Acidic: it is easy, but from a java perspective, not what you want. In the .NET world, structs are supposed to be immutable, so you should not allow for the the change of individual properties. The language supports changing individual properties, but since everything is passed by value, you always change the property on a copy of the struct, not the original (unless you use the `ref` or `out` keyword, but that would create really awkward code for changing the properties mutable structs). – Jeroen Wiert Pluimers Feb 13 '12 at 07:02
6

.NET data types are divided into value and reference types. Value types include int, byte, and structs. Reference types include string and classes.

structs are appropriate instead of classes when they just contain one or two value types (although even there you can have unintended side effects).

So structs are indeed passed by value and what you are seeing is expected.

Jonathan Wood
  • 65,341
  • 71
  • 269
  • 466
  • 1
    Sorry Strings are immutable are NOT passed by reference in terms of a reference generally understood. If it would be as you said, a string could be changed by some callee if passed as parameter! A class's fields, if passed as a parameter, can be changed, so it must be a reference and not a plain copy it. – Martin.Martinsson Apr 01 '16 at 09:14
  • 1
    @Martin: Strings are immutable as a class detail but they behave like any other object being passed as an object, and the string itself is not placed on the stack but a reference to its object. – Beeeaaar Feb 28 '17 at 21:57
5

Foreward: C# while managed still has the core memory idioms created by C. Memory can be reasonably viewed as a giant array where the index in the array is labeled the "memory address". A pointer is a numeric index of this array aka a memory address. The values in this array can either by data or a pointer to another memory address. A const pointer is a value stored in this array at some index which cannot change. A memory address inherently exists and can never change however the value that is located at that address can always change if it is not const.

Pass by class

A class / reference type (which includes string) is passed by a const pointer reference. Mutation will affect all usages of this instance. You cannot change the address of the object. If you attempt to change the address with either assignment or new you will in effect create a local variable that shares the same name as the parameter in the current scope.

Pass by copy

Primitives / ValueTypes / structs (strings are neither even though they disingenuously pose as them) are completely copied when returned from a method, property, or received as a parameter. Mutation of a struct will never be shared. If a struct contains a class member, what is copied is the pointer reference. This member object would be mutable.

Primitives are never mutable. You cannot mutate 1 to 2, you can mutate the memory address that currently refers to 1 to the memory address of 2 in the current scope.

Pass by true reference

Requires the usage of out or ref keywords.

ref will allow you to alter the pointer a new object or assign an existing object. ref will also allow you to pass a primitive / ValueType / struct by it's memory pointer to avoid copying the object. It would also allow you to replace the pointer to a different primitive if you assign to it.

out is semantically identical to ref with one minor difference. ref parameters are required to be initialized where out parameters are allowed to uninitialized as they are required to be initialized in the method that accepts the parameter. This is commonly shown in the TryParse methods and eliminates the need for you to have int x = 0; int.TryParse("5", out x) when the initial value of x would serve no purpose.

Chris Marisic
  • 32,487
  • 24
  • 164
  • 258
  • 1
    Managed references are semantically different from pointers or anything else a storage location can hold. If a valid pointer holds bit pattern 0x12345678, then as long as the pointer remains valid bit pattern 0x12345678 will continue to identify the same object. By contrast, the GC may change the bit patterns necessary to identify managed objects at any time, provided that it modifies the bit patterns stored in every reachable reference to make it keep identifying the same object. – supercat Mar 26 '15 at 17:39
  • Adding to what @supercat notes, in fact you can even have (managed) references to (unsafe) native pointers (but not the reverse, obviously), and this includes by using the new **C#7** [ref local](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-7#ref-locals-and-returns) feature: `int i; int *pi = &i; ref int* rpi = ref pi;` – Glenn Slayden Nov 25 '17 at 04:08
3

Just to illustrate the different effects of passing struct vs class through methods:

(note: tested in LINQPad 4)

Example

/// via http://stackoverflow.com/questions/9251608/are-structs-pass-by-value
void Main() {

    // just confirming with delegates
    Action<StructTransport> delegateTryUpdateValueType = (t) => {
        t.i += 10;
        t.s += ", appended delegate";
    };

    Action<ClassTransport> delegateTryUpdateRefType = (t) => {
        t.i += 10;
        t.s += ", appended delegate";
    };

    // initial state
    var structObject = new StructTransport { i = 1, s = "one" };
    var classObject = new ClassTransport { i = 2, s = "two" };

    structObject.Dump("Value Type - initial");
    classObject.Dump("Reference Type - initial");

    // make some changes!
    delegateTryUpdateValueType(structObject);
    delegateTryUpdateRefType(classObject);

    structObject.Dump("Value Type - after delegate");
    classObject.Dump("Reference Type - after delegate");

    methodTryUpdateValueType(structObject);
    methodTryUpdateRefType(classObject);

    structObject.Dump("Value Type - after method");
    classObject.Dump("Reference Type - after method");

    methodTryUpdateValueTypePassByRef(ref structObject);
    methodTryUpdateRefTypePassByRef(ref classObject);

    structObject.Dump("Value Type - after method passed-by-ref");
    classObject.Dump("Reference Type - after method passed-by-ref");
}

// the constructs
public struct StructTransport {
    public int i { get; set; }
    public string s { get; set; }
}
public class ClassTransport {
    public int i { get; set; }
    public string s { get; set; }
}

// the methods
public void methodTryUpdateValueType(StructTransport t) {
    t.i += 100;
    t.s += ", appended method";
}

public void methodTryUpdateRefType(ClassTransport t) {
    t.i += 100;
    t.s += ", appended method";
}

public void methodTryUpdateValueTypePassByRef(ref StructTransport t) {
    t.i += 1000;
    t.s += ", appended method by ref";
}

public void methodTryUpdateRefTypePassByRef(ref ClassTransport t) {
    t.i += 1000;
    t.s += ", appended method by ref";
}

Results

(from LINQPad Dump)

Value Type - initial 
StructTransport 
UserQuery+StructTransport 
i 1 
s one 


Reference Type - initial 
ClassTransport 
UserQuery+ClassTransport 
i 2 
s two 

//------------------------

Value Type - after delegate 
StructTransport 
UserQuery+StructTransport 
i 1 
s one 


Reference Type - after delegate 
ClassTransport 
UserQuery+ClassTransport 
i 12 
s two, appended delegate 

//------------------------

Value Type - after method 
StructTransport 
UserQuery+StructTransport 
i 1 
s one 


Reference Type - after method 
ClassTransport 
UserQuery+ClassTransport 
i 112 
s two, appended delegate, appended method 

//------------------------

Value Type - after method passed-by-ref 
StructTransport 
UserQuery+StructTransport 
i 1001 
s one, appended method by ref 


Reference Type - after method passed-by-ref 
ClassTransport 
UserQuery+ClassTransport 
i 1112 
s two, appended delegate, appended method, appended method by ref 
drzaus
  • 24,171
  • 16
  • 142
  • 201
2

The problem is, that the getter returns a copy of Vector2. If you change the coordinates like this

obj.Position.X = x;
obj.Position.Y = y;

You only change the coordinates of this ephemeral copy.

Do this instead

obj.Position = new Vector2(x, y);

This has nothing to do with by value or by reference. Value2 is a value type and get returns this value. If the vector had a reference type (class), get would return this reference. return returns values by value. If we have a reference type, then these references are the values and are returned.

Olivier Jacot-Descombes
  • 104,806
  • 13
  • 138
  • 188
  • But this forces me to create a new object everytime I want to to change the value of the field. Eww. – Acidic Feb 12 '12 at 18:58
  • 1
    It is not an object, so no new object is created; however, the constructor initializes the vector. – Olivier Jacot-Descombes Feb 12 '12 at 19:04
  • 6
    Of course it is an object. Why would you suppose that an instance of a struct is not an object? – Eric Lippert Feb 12 '12 at 19:51
  • I think of objects as reference types, as instances of classes. – Olivier Jacot-Descombes Feb 12 '12 at 19:53
  • 6
    @Acidic: If you are changing **the value** of the field then change **the value** of the field! Vectors are logically immutable, just like integers. You don't think "I'm going to change the number 12 so that it is now 13". You think "I'm going to replace the integer stored in this variable, 12, with a new integer, 13." Don't think "I'm going to mutate (1,2) to (1,3)". Think "I'm going to replace the vector in this variable, (1,2) with a different vector (1,3)." **Think about values as values**. – Eric Lippert Feb 12 '12 at 19:54
  • 3
    If it pleases you to believe the falsehood that structs are not objects, you go ahead and have that pleasant belief. I recommend against teaching that falsehood to others though; it seems likely to confuse them. – Eric Lippert Feb 12 '12 at 19:57
  • Wikipedia says [Object (computer science)](http://en.wikipedia.org/wiki/Object_(computer_science)), "In computer science, an object is any entity that can be manipulated by the commands of a programming language, such as a value, variable, function, or data structure. (With the later introduction of object-oriented programming the same word, 'object', refers to a particular instance of a class)". – Olivier Jacot-Descombes Feb 12 '12 at 20:08
  • 2
    @Eric Glad to hear you say that. However, it has been pointed out to me before that the MSDN (at least [in some places](http://msdn.microsoft.com/en-us/library/490f96s2.aspx)) makes the same distinction as Olivier here, and refers as “object” specifically to reference types. – Konrad Rudolph Feb 12 '12 at 20:28
  • @Eric: Storage locations of value types hold values, not objects. Every structure type has a corresponding class type (which inherits from ValueType) into which it is implicitly convertible, but storage locations of value type can't hold those. A variable of type `Point` holds 32 bits for an `X` value and 32 bits for a `Y` value. No sign of any managed object, or `Object`, or any other such thing anywhere. A `Point` may be implicitly cast to `ValueType` or `Object`, but a point which has been so cast is a different type from a `Point` which could sit in a storage location. – supercat Feb 12 '12 at 22:14
  • 3
    @Olivier: That wikipedia definition is terrible. In C#, instances of structs are objects. – Eric Lippert Feb 13 '12 at 02:13
  • 1
    @Konrad: Thanks for the link; I'll follow up with the documentation manager. – Eric Lippert Feb 13 '12 at 02:14
  • 6
    @supercat: storage locations of value types hold values. **Values of value type are objects.** This idea that you have that there is a "corresponding class type" is very Java-ish, and is a pleasant fiction, but it is a fiction. If you and Olivier enjoy believing this pleasant fiction, that's fine with me, but I'd find it unfortunate that you'd want to teach it to others. The implementation details of how a value is laid out in memory have nothing whatsoever to do with whether a thing is an "object" or not. – Eric Lippert Feb 13 '12 at 02:17
  • @EricLippert: If a conversion of one thing to some particular type (e.g. `IEnumerator`) is reference-preserving and conversion of another things to that same type is not reference preserving, I would regard the two things as being of semantically-different types. The system may in one case use the name `List.Enumerator` to refer to the type of an object instance on the heap, and in the other case use the same name to refer to the type of the storage location holding the thing, but the former type of thing will exhibit class semantics and the latter will exhibit value semantics. – supercat Feb 13 '12 at 07:53
  • @EricLippert: I would suggest that part of the definition of inheritance is that if type `X` inherits from `Y`, casts from `Y` to `X` or vice versa will be representation-preserving; if a cast from `X` to `Y` or from `Y` to `X` is anything but representation-preserving, that implies that neither `X` nor `Y` inherits from the other. Boxed structures clearly inherit from `ValueType`, and they meet that requirement (they also exhibit reference semantics). The things stored in storage locations of struct types, however, do not meet that requirement. – supercat Feb 13 '12 at 08:09
  • 3
    @supercat if you define inheritance to mean something different from its definition on the c# type system, then you will arrive at a conclusion that is different than the one dictated by the definition of the c# type system, and relatively meaningless in the context of that system. – phoog Feb 13 '12 at 14:30
  • 5
    @supercat: That is **absolutely not** the definition of "inheritance" in C#. And so phoog is correct -- if you start with a completely different definition, then you're going to arrive at completely different conclusions. You are free to use any definition you like, but again, when you teach it to other people, you're just impeding their ability to communicate with people who have already agreed to use the definition in the specification. – Eric Lippert Feb 13 '12 at 14:45
  • I think that we have to make a distinction between objects in the .NET type system and objects as a general concept in object-oriented programming. In .NET, all types derive directly or indirectly from `System.Object` and are therefore objects. However, you can find many sources that conceptually define objects as instances of classes. Just one example, [American National Standard Dictionary of Information Technology (ANSDIT) - The letter “O”](http://www.incits.org/ANSDIT/o1.htm): "In object-oriented programming, an object is an instance corresponding to a class definition." – Olivier Jacot-Descombes Feb 13 '12 at 14:57
  • the confusion here likely rest on the overload of the word class which has meaning in the type system but also is the means of defining a reference type, as opposed to as value type. @Eric's definition for c# is of course going to be correct he 'works on it for a living'. It is unfortunate that there are some 'leaks' in the abstraction between the "world of c# according to the type system" and the world of c# at other points where there is some messy behaviors. For me a classic case is the System.Enum type, which is indeed a type, but constraints refuse to play nice with it – ShuggyCoUk Feb 13 '12 at 15:45
  • @OlivierJacot-Descombes "class" has a domain-specific meaning in C# where it is contrasted with "struct"; we should be careful *not* to extend that to the word "class" in general discussions of OOP. This is relevant to a question I've been thinking of asking: in c# is there a word that encompasses both classes and structs (i.e., types whose fields we define and where we can write methods and properties)? For example, C# might have been defined with declarations as `class val` instead of `struct` and `class ref` instead of `class` without misusing the general OOP concept of "class". – phoog Feb 13 '12 at 16:00
  • @OlivierJacot-Descombes Perhaps this is unwelcome muddying of the waters, but I feel compelled to point out that not all types derive from System.Object -- interface types, for example. All *values* are of a type that derives from `object` (outside unsafe code, since pointers do not derive from object). See Eric's blog: http://blogs.msdn.com/b/ericlippert/archive/2009/08/06/not-everything-derives-from-object.aspx – phoog Feb 13 '12 at 16:12
  • @ShuggyCoUk: The type system uses the same `Type` object to describe storage locations (fields, etc.) of e.g. type `List.Enumerator`, and boxed heap instances of `List.Enumerator`, but they behave differently. The differences are most apparent with mutable structs (probably why Mr. Lippert hates them--they present a major leak in the "unified type system" abstraction) but can be demonstrated even with immutable structs (e.g. `KeyValuePair`). – supercat Feb 13 '12 at 16:12
  • @EricLippert: Given a boxed instance of `List.Enumerator`, would there be any way *without using Reflection* of determining whether it was a class type or value type? As far as I can tell, in all scenarios not involving Reflection, a boxed instance of that type will in every way behave exactly as it would if it were a class. If one were to use Reflection to get the type of that instance and create an array of that type, the array elements would behave as value types, but I can't think of any non-Reflection scenarios where it would behave as value type. Can you? – supercat Feb 13 '12 at 16:24
  • @supercat: I don't understand precisely what you mean by "given a boxed instance of". There are two storages involved and they have different types. The storage that contains *the reference to the box* is, say, a storage of type object. The reference refers to some storage location; that storage location is logically a variable of value type. (That as an implementation detail there is other stuff nearby in memory, like a vtable, and so on, is an implementation detail.) I'm not following your train of thought here. – Eric Lippert Feb 13 '12 at 16:38
  • @supercat: But more specifically, the answer to your question is an unqualified yes. If you have a reference to object, and you want to know whether that object is a boxed `List.Enumerator` then *unbox it* and you'll know. If the unboxing succeeds, it is; if it fails, then it is not. That's clearly different behaviour. But I think I am still not following your point. – Eric Lippert Feb 13 '12 at 16:42
  • @EricLippert: If a routine that takes a parameter of type `IEnumerator`, would there be any way, without using Reflection, to determine whether a passed-in instance was a class type or a boxed structure type, if one didn't know exactly *what* structure type it might be? I believe that in all scenarios not involving Reflection, `dynamic`, etc. the behavior of a boxed structure type stored in a location of type `IEnumerator` will be indistinguishable from that of a class-type object stored likewise. In what regard, if any, would such a struct instance not behave as a class object? – supercat Feb 13 '12 at 17:04
  • @supercat: Sure, it would behave like a reference. Since *you passed a reference* to the method, that's unsurprising! The whole *point* of interfaces is to enable the building of abstractions so that you don't have to care about the implementation details. But if you're going to box your value types so that you can treat them as classes, then why not simply make them classes in the first place and skip the expense of boxing? – Eric Lippert Feb 13 '12 at 17:08
  • @EricLippert: Also, I found the quote I was looking for, from http://msdn.microsoft.com/en-us/library/34yytbws%28VS.85%29.aspx which reads, "For each value type, the runtime supplies a corresponding boxed type, which is a class that has the same state and behavior as the value type." To me, that says if I define a `struct foo`, the system will create a 'boxed `foo`' class with the same fields and methods as my struct. – supercat Feb 13 '12 at 17:13
  • @supercat: That is certainly not how I would have chosen to describe the feature. That seems to be describing an implementation detail, and the way it describes it is contrary to the C# specification. The spec says: **The actual process of boxing a value of a non-nullable-value-type is best explained by imagining the existence of a generic boxing class ... A boxing class like Box above doesn’t actually exist and the dynamic type of a boxed value isn’t actually a class type.** Thanks for bringing this to my attention; I will have a talk with the documentation manager. – Eric Lippert Feb 13 '12 at 17:19
  • @EricLippert that description comes from the CLR spec 8.2.4 "Boxing and unboxing of values" http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-335.pdf – phoog Feb 13 '12 at 17:32
  • @EricLippert also note the table in section 8.2.2 which describes `object` as "Object or boxed value type". – phoog Feb 13 '12 at 17:34
  • @EricLippert: I think the .net type-system design is pretty good, given the constraint that it must be possible to zero-initialize or bit-copy all types of fields. It's better than Java's, not "in spite of" the fact that value types have different semantics from heap objects, but in significant measure *because* of that. In many cases, the unified-type-system abstraction is convenient, but to use it safely one should understand the ways in which it is "leaky". – supercat Feb 13 '12 at 17:37
  • @phoog: You are right in pointing out that only "concrete" types derive from `System.Object`. Interesting link to Eric's blog! – Olivier Jacot-Descombes Feb 13 '12 at 18:04
  • @OlivierJacot-Descombes: There are three contexts in which type "names" may be used: as storage locations or generic param types, object instances, and generic constraints. Class type "names" have essentially the same meaning in all three cases. Struct type names have different meanings when applied to instances vs other uses; interface have different meanings when applied to constraints vs other uses. Value types effectively inherit from `Object` only when used to describe heap instances. Interfaces effectively inherit from `Object` except when used as constraints. – supercat Feb 13 '12 at 18:18
  • 2
    @supercat: Value types **always** logically derive from `Object`. This has nothing to do with the heap or with boxing. The heap is just an implementation detail. – Olivier Jacot-Descombes Feb 13 '12 at 19:00
  • @EricLippert How much of this comment thread do you think could be deleted? It's getting rather long and I'd like to capture the relevant information in the question/answer. – casperOne Feb 13 '12 at 19:10
  • @supercat How much of this comment thread do you think could be deleted? It's getting rather long and I'd like to capture the relevant information in the question/answer. – casperOne Feb 13 '12 at 19:10
  • @OlivierJacot-Descombes How much of this comment thread do you think could be deleted? It's getting rather long and I'd like to capture the relevant information in the question/answer. – casperOne Feb 13 '12 at 19:10
  • @casperOne: There are different threads (or topics) here. You could logically group the comments by thread (or topic) and keep them all. – Olivier Jacot-Descombes Feb 13 '12 at 19:26
  • @OlivierJacot-Descombes Unfortunately, that's not really an option, if they are separate topics, then they shouldn't be attached to the question (might I recommend [chat](http://chat.stackoverflow.com)?). Right now, the comments contain multiple extended discussion which is not what the purpose of comments is for. – casperOne Feb 13 '12 at 19:29
  • @supercat "Value types effectively inherit from Object only when used to describe heap instances" not true. pray do tell how `1.ToString();` works. It never boxes. – ShuggyCoUk Feb 13 '12 at 19:32
  • 1
    @supercat. If that's too 'obvious' (the compiler inserts the explicit non virtual call) how's this `class Foo { public static void Blah(T t) { t.ToString();} }` with `Foo.Blah(1);` I assure you, no boxing happens and it's a callvirt – ShuggyCoUk Feb 13 '12 at 19:33
  • @ShuggyCoUk: This is getting off the subject of the original questioner's comment (which mainly relates to the fact that struct values are not "objects" in the sense that .net uses the term, even if C# may use the term differently), but `Foo.Blah(3)` will cause the JITter to generate code for a routine with a static call to `Int32.ToString()`, `Foo.Blah(7u)` will make it generate one with a static call to `UInt32.ToString()`, etc. No virtual dispatch within the routines themselves. – supercat Feb 13 '12 at 19:52
  • Well, I learned something new today; I had no idea that the CLR spec had such an odd description of the result of boxing. The C# spec description seems much more sensible to me, but at least I understand the source of the confusion now! Thanks all for an interesting discussion. – Eric Lippert Feb 13 '12 at 20:14
  • @EricLippert that part of the CLR spec was also cited in comments to your answer of just over a month ago: http://stackoverflow.com/a/8810267/385844 – phoog Feb 13 '12 at 22:38
  • @EricLippert: The CLR spec's description of how value types are implemented may seem "odd", but from what I can tell it accurately describes the way things behave. The notion that "everything is an object" may seem convenient, and C# may endeavor to uphold such an abstraction, but CLR is not Java. Value types exist and they have semantics which usefully differ from objects. There are deficiencies in the CLR handling of value types, some of which can cause confusion, but rather than denouncing anything which differs from "object" behavior as "evil", one should work to fix those deficiencies. – supercat Feb 14 '12 at 23:58
  • @EricLippert: Much confusion involving mutable structs, for example, could be easily resolved by defining attributes to indicate whether methods/properties might modify `this`, and forbidding use of `this`-mutating methods/properties on values. The assumption that property setters will modify `this` but other methods won't is often correct, but there are exceptions both ways; allowing attributes to clear up such exceptions would be helpful. – supercat Feb 15 '12 at 00:09
2

Yes, structs inherit from ValueType, and are passed by value. This is true for primitive types as well - int, double, bool, etc (but not string). Strings, arrays and all classes are reference types, and are passed by reference.

If you want to pass a struct by ref, using the ref keyword:

public void MyMethod (ref Vector2 position)

which will pass the struct by-ref, and allow you to modify its members.

Avner Shahar-Kashtan
  • 14,492
  • 3
  • 37
  • 63
  • 2
    You will only be able to modify its members if it is mutable. Mutable structs are generally discouraged. Furthermore, it is not possible to pass a property by reference. – phoog Feb 12 '12 at 19:02
  • That's true, but note the actual question in the OP: what is passed by ref, what is passed by val. – Avner Shahar-Kashtan Feb 12 '12 at 19:04
  • @phoog: You can modify the members of a struct passed as `ref` regardless of whether the struct is supposedly "immutable". For example, `void Blah(ref KeyValuePair z){z = new KeyValuePair(3,4);}` – supercat Feb 12 '12 at 22:55
  • 1
    @supercat, that is not modifying a member of the struct, that's assigning a new value to the (entire) struct. – phoog Feb 13 '12 at 05:15
  • @phoog: It's modifying all members of the struct, in rapid succession, though not necessarily simultaneously. For example, suppose a class has a field `Boz` of type `KeyValuePair, initially set to ("James","Stewart") and one thread performs `Boz.ToString()` while another thread performs `Boz = new KeyValuePair("Donna","Reed"). If `KeyValuePair` were really immutable, there should be no way for the first thread to output "[James, Reed]"; in fact, though, the second thread will overwrite the fields of the very thing performing `ToString`. – supercat Feb 13 '12 at 08:35
  • 1
    @supercat what if the struct has 2 members of 16 bits each? Then the write is atomic, and what you say couldn't happen. Non-atomic writes do not imply mutability. Put another way: you are describing a threading scenario in which a thread reads a value in an invalid state, and claiming that it is mutation of an immutable struct. It's not mutation, it's logically invalid data. What if it were a 64-bit integer? The analogous error could happen; does that make Int64 mutable? No, it makes it non-atomic. – phoog Feb 13 '12 at 14:48
  • @phoog: An `Int64` isn't really immutable. `Int64[] l[]={0x1111004444001111}; System.Buffer.BlockCopy(l, 0, l, 3, 2);` I would describe the second statement as mutating the instance of `Int64` stored in `l[0]`. Another thread could use `BlockCopy` to update some other byte simultaneously, and the two writes would be guaranteed not to interfere--something which could not be guaranteed if the former BlockCopy were creating and storing a new instance of `Int64`. Besides, the same behavior would be observable with `KeyValuePair` even if it were written atomically. – supercat Feb 13 '12 at 18:40
  • 1
    @supercat Nothing is immutable except ROM if you want to look at it that way. If you go outside the type system with BlockCopy to modify data, that doesn't tell you anything about how data behaves within the type system. How do you propose that `KeyValuePair` would allow a thread to read (1, 4) when another thread is overwriting (1, 2) with (3, 4)? The write is atomic! – phoog Feb 13 '12 at 18:50
  • @phoog: Going outside the type system would imply `unsafe` code. The behavior of `BlockCopy` is defined within the type system (except possibly for byte-ordering, so my example was byte-order agnostic). As for the 32-bit struct, it doesn't matter if the write is atomic if it can occur between the time the other thread reads the first half and the time it reads the second (e.g. while the struct's `ToString()` method is calling `ToString()` on the first element). – supercat Feb 13 '12 at 19:22
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/7637/discussion-between-phoog-and-supercat) – phoog Feb 13 '12 at 19:27
1

Objects are passed by reference and structs by value. But note that you have the "out" and "ref" modifiers on arguments.

So you can pass a struct by reference like so:

public void fooBar( ref Vector2 position )
{
}
Dan Byström
  • 9,067
  • 5
  • 38
  • 68
0

Every storage location of a structure type holds all the fields, private and public, of that struct. Passing a parameter of a structure type entails allocating space for that structure on the stack and copying all of the fields from the structure to the stack.

With regard to working with structures stored within a collection, using mutable structs with the existing collections generally requires reading out a struct to a local copy, mutating that copy, and the storing it back. Assuming MyList is a List<Point>, and one wants to add some local variable z to MyList[3].X:

  Point temp = MyList[3];
  temp.X += Z;
  MyList[3] = temp;

This is mildly annoying, but is often cleaner, safer, and more efficient than using immutable structs, way more efficient than immutable class objects, and way safer than using mutable class objects. I'd really like to see compiler support for a better way for collections to expose value-type elements. There are ways of writing efficient code to handle such exposure with good semantics (e.g. a collection object could react when elements were updated, without requiring those elements to have any link to the collection) but the code reads horribly. Adding compiler support in a manner conceptually similar to closures would allow efficient code to also be readable.

Note that contrary to what some people claim, a structure is fundamentally different from a class-type object, but for every structure type there is a corresponding type, sometimes referred to as a "boxed structure", which derives from Object (see the CLI (Common Language Infrastructure) specification, sections 8.2.4 and 8.9.7). Although the compiler will implicitly convert any struct into its corresponding boxed type when necessary to pass it to code that expects a reference to a class-type object, will allow references to boxed structs to have their contents copied into real structs, and will sometimes allow code to work with boxed structs directly, boxed structs behave like class objects, because that's what they are.

supercat
  • 77,689
  • 9
  • 166
  • 211
  • As Eric Lippert has pointed out, your terminology is not standard (e.g. "object type" should be "reference type"). In addition, in the context of C# (as opposed to .NET in general), you really don't ever need to think about boxed types. Values of value type undergo a boxing conversion if they are stored in variables of reference type (e.g. `System.ValueType`, `System.Enum`, or `System.Object`), but the fact that this involves a transient boxed type when it comes to the IL type system is an irrelevant implementation detail when it comes to understanding the behavior of C# code. – kvb Feb 13 '12 at 15:39
  • @kvb while it may not be necessary to think about the *implementation details* of boxed types, you do need to think somewhat about their semantics. You wouldn't be able to teach c# programming without introducing the concept of boxed types, for example. How else would you explain that `(short)(object)1` throws an `InvalidCastException`? – phoog Feb 13 '12 at 16:18
  • In this example, you don't even need the concept of _boxing_, not to mention _boxed types_, to describe what's going on. `(short)(object)1` throws an exception because `(object)1` is an object containing a value of runtime type `int`, not a value of runtime type `short`. This is analogous to why `(short)(object)"test"`, or `(string)(object)1`, or `(System.Attribute)(object)"test"` throw exceptions. Boxing doesn't really have anything to do with this behavior. – kvb Feb 13 '12 at 17:16
  • In general, the concept of _boxing_ (i.e. storing a value of value type in a storage location of reference type) is most relevant when explaining the behavior of mutable structs. _Boxed types_ (i.e. the IL verification types that correspond to each value type), on the other hand, are really never needed to describe how C# works. The fact that the verifier knows that `int` is boxed to a `boxed int` on route to being stored as an `object` is an irrelevant implementation detail. – kvb Feb 13 '12 at 17:27
  • The terminology gets tricky here, because I think it's accurate to say that `(object)1` is a _boxed_ int (that is, an `int` value which has been boxed). However, it's not accurate to say that it's an instance of type _boxed int_; it's an instance of type `object`. The boxed types never appear as storage locations, so they really don't come into play at the C# level. – kvb Feb 13 '12 at 17:30
  • @kvb: I consider "implementation details" to be things which do not affect behavior in any *standard-defined behavior*. If one has two variables of generic type `T:IEnumerator`, and one copies the first to the second, the standard specifies that in some cases it *must* copy the state of the enumerator, and in other cases the two variables *must* alias the same state. The question of whether the state gets copied is not an "implementation detail"--it's standards-defined behavior. – supercat Feb 13 '12 at 19:34
  • @kvb: `(object)1` is stored as a heap object of type `System.Int32`, i.e. a boxed integer. This may be confirmed by calling `GetType()` on it. When `GetType()` returns `System.Int32`, that means it was called on a boxed instance of `Int32`; even if one calls `5.GetType()`, the system boxes the `5` before calling `GetType()`, so `GetType()` is still called on a boxed instance of `Int32`. – supercat Feb 13 '12 at 19:38
  • Regarding implementation details, I'm not sure what you mean. My comment on not needing the concept of boxing for the example was meant to be directed at phoog, if that's the cause of any confusion... – kvb Feb 13 '12 at 20:38
  • Regarding your latest comment, I think I agree with you, but this is where the terminology gets confusing. `(object)1` is a "boxed" integer (an integer that has been boxed), but is not a "boxed integer" (an instance of the "boxed integer" verification type) - the type of the storage location or temporary is `object`, and the runtime type of the instance is `Int32`, as you point out. As the ECMA CLI spec points out, boxed types are _transient_ and only ever occur on the evaluation stack; they are really only needed to understand the whether a sequence of IL instructions is valid. – kvb Feb 13 '12 at 20:53
  • However, in looking at the CLI spec again, I realize that the terminology is a bit muddled and I owe you an apology - they _do_ use the term "object type". – kvb Feb 13 '12 at 21:01
  • @kvb: Storage locations of 'boxed type' may only exist as a transient concept, but casting a struct-type value to `Object` generates a persistent instance of an object whose class derives from `System.ValueType` and will be described by the same `Type` object that described the storage location holding the original value. I added a link to the CLI spec; sections 8.9.7 and 8.6.1.5 are interesting. How do you like my edits above? – supercat Feb 13 '12 at 21:24
  • That's true, and I think at the IL level your description is fine. – kvb Feb 14 '12 at 16:38
  • @kvb: Is there anything you'd change in my answer? It doesn't seem to be very popular. I wonder some people's real objection to mutable value types is that, to the extent that the CLS spec and behavior are inconsistent with the C# abstraction of all types being inherited from Object, they view the former as defective, and scorn anything that would contradict the Java-style "everything is Object" view. – supercat Feb 14 '12 at 17:55
  • @kvb: The mutable value semantics in .net are unfortunately rather limited by the requirements that all value objects must be blittable, and must accept zero-initialization as an acceptable default state. They are further constrained by the inability to declare methods as accepting `this` by value, ref, or const-ref (note that being able to declare methods on heap-ref types as accepting `this` by ref would allow immutable heap-ref types to better mimic value semantics). Despite their problems, though, I still consider them 'useful'. – supercat Feb 14 '12 at 18:03
  • Regarding the popularity of your answer, it may not be that the content is incorrect, but that it doesn't seem to directly address the issues brought up in the question. For example, your workaround is useful, but you don't explain why it's necessary in any detail, and your last paragraph discusses boxing which isn't directly related to the question. The OP's confusion seems to stem from fairly complete unfamiliarity with the semantics of value types, and I'm not sure that your answer is targetted at a level that he/she would understand. – kvb Feb 14 '12 at 18:56
  • @kvb: I was attempting to tailor my answer toward some of the OP's confusion relayed in his comments to other questions; I can see where it could appear somewhat lacking with regard to the question above it. The workaround, though, seems directly targeted toward what the OP is asking, and immediately above the three lines of code, I describe the three steps represented thereby: read out a struct, mutate it, and write it back. With regard to the last paragraph, I want to steer any readers away from the philosophy that... – supercat Feb 14 '12 at 19:26
  • ...everything should be thought of as behaving like Object, except for some things which are evil and defective, and instead encourage people to recognize that they should be aware of types other than Object, and should learn how such types work and use them when it's appropriate to do so. – supercat Feb 14 '12 at 19:31