views:

1043

answers:

7

I am writing an application in C# which is going to do extensive calculations. Everything is going around basic struct - Value. It is basically double with some additional parameters (accuracy etc.) It has to be a struct, because there will be too many of them created to afford heap allocation. Now, I need to make sure they all are correctly initialized. I cannot declare default explicit constructor, though I am provided default constructor, which initializes everything with 0, which does not make sense in my domain.

And there is no way to deny creating an instance without calling my constructor with parameters either...?

Basically what I need is this test to pass:

[Test]
public void HowDoesThisStructureInitializeByDefault()
{
   Value v = new Value(); - if this did not compile - it would have been ok!

   Assert.AreEqual(0, v.Val); - passes
   Assert.AreEqual(-1, v.Accuracy); - fails
}

It would be OK to throw an exception if no constructor has been explicitly called and structure is still accessed, but checking that all the time would take too much time.

I am almost losing hope now, please help!

A: 

Are you hoping to initialize the accuracy to -1 with a default constructor? I don't think you can stop someone from using new Value(), but you could add a constructor that lets you use new Value(10) and have the accuracy initialized the way you want.

See the MSDN page about Struct Constructors.

You could always throw an exception in the code that uses your structure if you encounter an accuracy of 0 (if that value never makes sense!).

Aaron
+2  A: 

I don't think C# allows you to create default constructors on value types. There are several questions related to your issue:

There is a way of doing it in the IL, but initializing arrays still won't call these constructors.

Filip
This is actually a restriction in the core CLR, not C#.
JaredPar
Jared: It's a mixture. IL *does* let you define a parameterless constructor (even a non-public one) and it will be called if you write new Value() in C# - but it won't be called when initializing an array. I was quite surprised by the first part as well though...
Jon Skeet
+4  A: 

Why can't you define an explicit constructor? This is what they're for. Moreover, why do you think you "can't afford heap allocation"? Heap allocation is very cheap in managed languages. How have you tested this assumption that you can't afford heap allocation, or indeed that heap allocation is more expensive in the first place?

(For a type consisting of "a double and several parameters", I suspect you're up in a size where heap allocation is actually cheaper and more efficient)

In any case, you can't prevent a user from calling the default constructor on a value type, if he so desires. All you can do is make sure that a better way to initialize the value exists, such as a non-default constructor, or if you can't create one for whatever reason, a function which creates and initializes your value type when called.

But of course, you have no guarantees that people actually call it.

Edit: Heap allocation in .NET basically consists of just a simple stack push operation. That's the nice thing about managed (and garbage-collected) languages. The runtime essentially uses a big stack as its heap, so each allocation just increments the stack pointer a bit (after checking that there's enough free memory, of course). The garbage collector then takes care of compacting the memory when necessary.

So the heap allocation itself is ridiculously cheap. Of course, the additional GC pressure might slow you down again (Although as far as I know, the time required for a GC pass depends only on the number of live object, not on the ones to be GC'ed, so having countless "dead" objects lying around may not be a big problem), but on the other hand, stack allocation isn't free either. Value types are passed by value, so every time you pass your type as a parameter to a function, or return it, a copy has to be made. I don't know how big your value is, but a double is 8 bytes, and given that you have a few extra parameters, I'll assume 32 bytes. That might be so big that the extra copying required for valuetypes makes it slower than if you'd used heap allocation. Perhaps.

As you can see, there are advantages to both value- and reference-types. I can't say which one is faster in your case, but if I were you, I'd be very careful making this kind of assumptions. If possible, structure your code so you can switch between a reference- and valuetype implementation, and see which works best. Alternatively, write smaller tests to try to predict how each would perform on a large scale.

jalf
@jalf - 1) I can't define explicit constructor because C# does not allow explicit constructors on structs. 2) I think heap allocation is moer expensive because you need to call something to do it. You might even get OutOfMemoryException.For stack allocation, you don't need to do anything,am I wrong?
badbadboy
Oh, I thought by explicit constructor you meant a non-default one. Define a constructor which takes arguments, and uses those to initialize the struct, and use that consistently then.I'm going to edit my post to be a bit more detailed about the costs of heap allocation, so please check that. :)
jalf
@jalf - thanks. Makes much sense now. Still, I'm imagining writing this kind of code in C++. You have an array Values, would you declare a regular array (stack) or an array of pointers (heap)? It's not just about allocation. You will have to find the object by ref everytime if doing heap..
badbadboy
Yeah, in C++ I'd definitely agree with stack allocation. And true, there's a pointer indirection and possibly a cache miss involved in referencing objects on the heap. Whether that is enough to make stack allocation more efficient can only be answered through testing.
jalf
+2  A: 

You can't get rid of the default constructor (Jon Skeet, of course, answered why very well at http://stackoverflow.com/questions/333829/why-cant-i-define-a-default-constructor-for-a-struct-in-net#333840), but you could create a factory class that allows you to define your structure values with properly initialized parameters. You could use unit tests with mock/verify to make sure that when new values are created by your code they use the factory. This would be a convention that you would need to enforce as the compiler will not enforce it for you.

public static class StructFactory
{
    public static Value DefaultValue()
    {
         Value v = new Value();
         v.Value = 0.0;
         v.Accuracy = 15; /* digits */
         return v;
    }
}

...

Value v = StructFactory.DefaultValue();
tvanfosson
@tvanfosson "You could use unit tests with mock/verify to make sure that when new values are created by your code they use the factory" - how can you ensure that everyone uses the factory? Without doing special check in the struct (which is expensive?)
badbadboy
For code you write, you can mock the factory and set up an expectation in your unit test that the factory method gets called. The point was that it's convention that has to be enforced outside the compiler. I'd also document it in the code so that people who use the structure understand how to.
tvanfosson
+2  A: 

Struct fields are initialized to zero (or null, or in general default(T)).

If you want the initial value of Accuracy to be -1, you could implement the Accuracy property such that when the underlying field == 0, the property returns -1.

One possibility:

struct Value
{
  int _accuracyPlusOne;

  public int Accuracy
  { 
    get { return _accuracyPlusOne - 1; }
    get { _accuracyPlusOne= value + 1; }
  }
}
mackenir
I genuinely can't tell if this solution is horrifying or brilliant.
Robert Rossney
@Robert: Actually, it's neither; rather, it's the normal way to implement this. `System.DateTime` does something similar.
Konrad Rudolph
+4  A: 

I know you're not asking this, but I have trouble believing you really need struct for performance. You owe it to yourself to write your code in the clearest, simplest way possible, and then profile before optimizing.

Jay Bazuzi
A: 

It has to be a struct, because there will be too many of them created to afford heap allocation.

Are you sure about that? Objects are cheap to create and delete in .NET.

Also, can you afford to use structs? They are far more expensive than objects to use because you have to copy the entire struct every time you pass them to a function. With objects, you only pass the pointer.

Jonathan Allen