Value types are types which do not have an identity. When one variable is modified, other instances are not.
Using Javascript syntax as an example, here is how a value type works.
var foo = { a: 42 };
var bar = foo;
bar.a = 0;
// foo.a is still 42
Reference types are types which do have an identity. When one variable is modified, other instances are as well.
Here is how a reference type works.
var foo = { a: 42 };
var bar = foo;
bar.a = 0;
// foo.a is now 0
Note how the example uses mutatable objects to show the difference. If the objects were immutable, you couldn't do that, so that kind of testing for value/reference types doesn't work.
Is there any functional difference between immutable value types and immutable reference types? Is there any algorithm that can tell the difference between a reference type and a value type if they are immutable? Reflection is cheating.
I'm wondering this mostly out of curiosity.
3 Answers 3
You are defining value types and reference in a language agnostic way, but doing so only by example in terms of changing of data members. Logically, making the types immutable makes you lose the only difference guaranteed by your definition (and the answer might be "no").
However, once we start looking at particular programming languages, then yes: there are more differences.
Consider the following C# example.
void increment()
{
lock (synchro)
{
total++;
}
}
private int total = 0;
private SomeType synchro;
If SomeType
is a reference type, this counter will be thread safe. If SomeType
is a value type, then, due to boxing, each thread is locking a copy of synchro
and increments may be lost under concurrency.
Of course, there are no genuine immutable types in .NET in the most abstract sense, as the monitors involved are implemented using hidden fields (akin to the C++ mutable
keyword that can declare mutable members in otherwise immutable types). But on Stack Overflow, everyone will understand your question to refer to anything that their platform calls "immutable".
-
I'm not following what you are saying about locking
synchro
. Did you mean tolock (synchro)
?Kendall Frey– Kendall Frey2012年06月06日 19:47:09 +00:00Commented Jun 6, 2012 at 19:47 -
Yes, I originally had
@lock
there but then inconsistently changed that as the@
would only puzzle non-C#-ists. Fixed.Jirka Hanika– Jirka Hanika2012年06月06日 19:58:04 +00:00Commented Jun 6, 2012 at 19:58
Yes, equality still differs:
a: value type = 4;
b: value type = 4;
c: reference type = 4;
d: reference type = 4;
a == b; // true;
c == d; // false;
C# cheats for things like strings by consolodating references that are equivalent, but this isn't strictly necessary for immutable reference types.
-
You assume that equality is always defined as referential equality. This is not true- languages can have operator overloads that change this definition.DeadMG– DeadMG2012年06月06日 20:30:18 +00:00Commented Jun 6, 2012 at 20:30
-
@DeadMG: I'm assuming that any language that has reference types will provide some reference equality mechanism (even if the common equality is structural). I'm not aware of any counter-examples?Telastyn– Telastyn2012年06月06日 20:32:09 +00:00Commented Jun 6, 2012 at 20:32
-
What's the point of saying "They're referentially inequivalent" when the user of the type will not use referential equality to compare them? C# can do this and C++ can do it too.DeadMG– DeadMG2012年06月06日 20:33:54 +00:00Commented Jun 6, 2012 at 20:33
-
@Telastyn: Well, Haskell doesn’t provide any reference-equality mechanism because it would violate referential transparency. You can implement it using
unsafePerformIO
if you’re willing to rely on implementation-defined behaviour, though, so I dunno if it counts as a counterexample.Jon Purdy– Jon Purdy2012年06月07日 03:20:41 +00:00Commented Jun 7, 2012 at 3:20 -
The C# equality operator is icky. In vb.net, one may only use the
=
operator to compare things whose types provide explicit support for such comparison; if one wants referential equality, one must use theIs
keyword. C# allows the==
operator for any class-type rvalues, but its meaning may or may not matchObject.Equals()
. Consider what happens if one passes strings topublic static bool IsEqual<T>(T obj1, T obj2) where T : class { return obj1 == obj2; }
. What sort of comparison is used?supercat– supercat2012年07月05日 19:40:11 +00:00Commented Jul 5, 2012 at 19:40
Value vs reference type is not a language-agnostic term. A language such as C++ and C does not hold a distinction- it is an arbitrary imposition of some languages. However, I'm gonna try and roll with it anyway.
A simple example is sizeof(T)
. All reference types have the size of a pointer (possibly plus the size of another pointer, depending on what your memory management system is). Value types, however, do not. In addition, you can measure performance characteristics to determine whether you are dealing with a value or a reference type. In addition, it's not particularly safe to refer to value types in some contexts.
Reference types can do some things that immutable value types cannot- for example, references to them can rebound to another instance.
class X {
const int imm;
X() : imm(0) {}
};
class Y {
const int* imm;
Y() : imm(new int(0));
};
X x;
Y y;
y.imm = new int(5); // Whoops! The reference itself is not immutable.
Fundamentally, it must always be known whether a type is a value or a reference, else you cannot generate the correct code to access it.
-
I'm not referring to languages with value types and pointers, but reference types, where a type definition specifies which is the case. E.g.
class
vsstruct
.Kendall Frey– Kendall Frey2012年06月06日 21:27:19 +00:00Commented Jun 6, 2012 at 21:27 -
@KendallFrey: Which is exactly why I said that it's not at all language-agnostic. Of course, my fundamental point still holds.DeadMG– DeadMG2012年06月07日 06:41:50 +00:00Commented Jun 7, 2012 at 6:41
-
The question of whether a type is stored as a value or a reference is largely orthogonal to the question of whether it behaves like one. In languages or frameworks where variable assignment calls a user-defined copy constructor, things which are stored as heap references can behave like mutable value types, and in just about any framework which supports user-defined value types, things which to the compiler look like value types can behave like reference types.supercat– supercat2012年07月05日 19:15:08 +00:00Commented Jul 5, 2012 at 19:15
-
With regard to immutable types, a well-designed language and framework should allow immutable value types and immutable class types to be used interchangeably, but .net and C# have some limitations. For an immutable class type to really behave like an immutable value type, its class members must be callable directly, without using
CallVirt
(so properties invoked on a null reference could yield meaningful defaults rather than crashing), and it should be usable as a type argument toNullable<T>
.supercat– supercat2012年07月05日 19:30:14 +00:00Commented Jul 5, 2012 at 19:30
Explore related questions
See similar questions with these tags.