LA.NET [EN]

Jul 14

In the previous post, I’ve talked about some interesting features that explain why reference type’s instance constructors behave the way they do. Today, we’ll keep looking at instance constructors, but we’ll concentrate on structs. Before going on, I’m assuming that you know the difference between value and reference types.

The first thing you should keep in mind is that there’s simply no way for you to prevent the instantiation of a value type. And this happens because you can only add non-parameterless constructors to your customs structs. Don’t even try to add a new parameterless constructor because the C# compiler will stop you immediately when you try to compile your project. Don’t believe me? Ok, try to compile this in C#:

struct Person {
    private Int32 __age;
    public Person(){ 
__age = 10;
} }


[Patiently waiting…]



Ok, we’re ready to keep going…You might be curious on why you can’t add a parameterless constructor to a struct. I was, especially after seeing that the CLR does allow you to add parameterless constructors to value types (ie, you can add a parameterless constructor to a value type, but you’ll need to use another language  – ex.: IL). I must confess that the best explanation I’ve read is in Jeffrey Richter’s fantastic  CLR via C# book (oh damn, I’ve forgot to write a review about it!). Suppose for a minute that we can define parameterless constructors to a value type. What would happen when you execute the following code (ok, never mind the example; concentrate only in the code):



public class Manager {
    private Person _person;
    public Manager() { }
}


If you’re expecting to see the Person’s constructor involved,then you better wait seated in a comfy chair :,). In order to improve runtime performance, constructors will only be  called if you call them explicitly  (compare this behavior with the one we have for reference types).  And according to Jeffrey, the team thought that this would confuse developers and opted for not allowing the definition of parameterless constructors in C#.



Now, it’s important to understand that you can still create parameter constructors for you custom structs. They do need to receive parameters and you must ensure that all the private fields are initialized. Take a look at the following snippet:



struct Color {
    private Byte _red;
    private Byte _green;
    private Byte _blue;
    private Byte __alpha;
    public Color(Byte red, Byte blue, Byte green) {
        _red = red;
        _blue = blue;
        _green = green;
    }
}


Anything wrong? Hell, yes! Since verifiable code “insists” that all fields must be written to before they’re read, you must initialize all the private fields from within all the instance constructors that have been added to a custom struct. So, the easiest thing you can do to make the previous code compile is initialize the _alpha field explicitly. Do notice that you must put the initialization code inside your constructor since the instance fields initializers aren’t permitted in value types.



Before ending, there’s still time for showing you an alternate way to initialize all the fields of a value type. Take a look at the following constructor for the Color struct:



public Color(Int32 alpha){
    this = new Color();
    _alpha= alpha;
}


I must confess that the first time I saw this I was really confused :) Ok, so what’s going on here? Glad you asked :) Calling new results in zeroing all the memory required for holding a Color object . You can then set the current instance to that new object. Not very readable, but it might save a few key strokes when you only want to explicitly initialize one of the fields of your struct.



One final note regarding initialization of value type fields in reference types: the CLR ensures that they’re always zeroed during initialization of that reference type. That doesn’t happen when we’re talking about value type fields in other value types. If you’re writing code in a “verifiable” language (ex.: C#), then you’re safe because the compiler will generate code that ensures that those types are zeroed out.



And I guess that’s it. After all, there were lots of things to say about structs instance constructors. Stay tuned for more!

Leave a Reply

Your email address will not be published. Required fields are marked *


*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>