views:

81

answers:

2

If you have an immutable type like this:

struct Point3
{

}

and a member inside like origin:

public static const Point3 Origin = new Point3 (0,0,0);

should you use:

new Point3 (0,0,0)

?

It seems to me that since the type can not be changed, why have many origins that are essentially the same thing? Like we never change 0, right?

How to achieve the same thing for immutable types?

+7  A: 
public static readonly Point3 Origin = new Point3(0,0,0);
Mehrdad Afshari
+1 But its not really "const", is it? ;)
Andrew Hare
It's close enough. The closest, probably :)
Mehrdad Afshari
Thanks, but why create new instances every time this is called? Or is it only called once, I mean the creation of a new Point3 upon accessing the Origin member.
Joan Venge
It won't create new instances. A struct is always copied, btw. It's its nature. But the constructor won't be called, so it's not really considered a new instance.
Mehrdad Afshari
It won't create a new instance each time it's used - it's a static readonly variable like any other; the static initializer is only executed once.
Jon Skeet
Thanks guys now I got it.
Joan Venge
+1  A: 

As Andrew mentioned, you can't use const for this because it's not a compile-time constant.

Note that if you are going to use a constructor repeatedly, you'd be better off (from a performance point of view) calling

new Point3()

than

new Point3(0, 0, 0)

The compiler knows that the first version is just going to blank out memory, and doesn't need to call any code.

However, I'd go along with providing an Origin member and using that everywhere instead, where possible :)

Jon Skeet
Thanks Jon. In the last line, you mean I should go ahead and use Origin with readonly and new Point3()?
Joan Venge
Btw Jon, why const can't be used with this? You can do const int a = 1, right? Why not new Point3() ?
Joan Venge
@Joan: Because there's no way to represent a Point3D literal in code.
Mehrdad Afshari
Thanks Mehrdad. You mean like 15f, or 15d like? Do you know why this is so? Like internally the compiler can't realize it's gonna be a literal?
Joan Venge
To create a Point3, the constructor should be called. The constructor is a *method* and the behavior is not necessarily known at compile time. You can only create constants with values of integral types, strings, `bool` and `null`. The reason I mentioned above is a high level view. The real reason is that there's no IL instruction to load a constant structure like that. For integers and bool, there's `ldc`, for null, we've 'ldnull', and for strings, we have 'ldstr'.
Mehrdad Afshari
Thanks Mehrdad. What does ld stand there? Also do you happen to know if JIT would be smart enough to optimize double setting of values, when one calls new Point3 (0,0,0) seeing that they are gonna be 0 already or set already? I suspect it wouldn't happen because Jon advised me to use new Point().
Joan Venge
I think Jon's advice is primarily due to improved readability and decreased chance of error. Regarding JIT optimization, I highly suspect it's smart enough to recognize that but I cannot say anything as I haven't checked the disassembly. `ld` means load. For example, ldc.i4.1 instruction will load a 4 byte `1` value on the stack.
Mehrdad Afshari
Thanks Mehrdad, very helpful. The thing that I assumed regarding JIT smartness was, that the property might do some other stuff that would be different if you do it once or twice, and I thought the JIT wouldn't optimize it so not to have side effects.
Joan Venge