tags:

views:

136

answers:

3

So I started reading Jon Skeet's 2nd edition of C# in depth and kind of confused about the following code in terms what it does and what is wrong with it (ch 13, section: Immutability and object initialization)

Message message = new Message(
"[email protected]",
"[email protected]",
"I hope you like the second edition")
{
       Subject = "A quick message"  // <=  {Subject = "A quick message"   }; what is it?
};

Elaboration on this topic, would help tremendously!

Would someone explain that?

+2  A: 

Well, the "Message" class is clearly mutable, as you are setting various properties; in the constructor and in the initialisation clause.

It's also confusing, I imagine, because he's setting the 'subject' field twice. Which one will be used?

Noon Silk
Setting anything in the constructor doesn't mean it's mutable... only the initialization clause means it's mutable.
Martinho Fernandes
True enough; my mistake.
Noon Silk
I don't understand the syntax: looks like he is passing the parameters and then he has open '... what does it mean?
vehomzzz
That's the object initialiser part. It sets properties of the object that's been created.
Noon Silk
+1 Is that correct, no semi colon followed Subject = "A quick message". what if you have multiple arguments? I would appreciate if you include this in your answer
vehomzzz
You mean multiple properties you want to set? Commas:prop1 = a,prop2 = b
Noon Silk
I'm not setting subject twice - I'm setting the body in the constructor and then setting the Subject property. It's not clear, because the arguments aren't named... which is one of the points I'm trying to make :)
Jon Skeet
+2  A: 

Let's look at it this way

 Message message = new Message(
    "[email protected]",
    "[email protected]",
    "I hope you like the second edition")

^^^ This part of the expression invokes the ctor of Message which takes 3 string parameters

 {
           Subject = "A quick message"  // <=  {Subject = "A quick message"   }; what is it?
    };

^^^ The next part then sets the Subject property on the new instance to the given value. This block is called the object initializer. You can set any property at most once in this block.

There are multiple way to initialize an object.. the following could all have the same effect. (Assumption: message class has public properties called From, To and Subject)

Message m = new Message() {From="F", To="T", Subject="Whatever"}; // default ctor followed by property setters
Message m = new Message {From="F", To="T", Subject="Whatever"}; // allowed to omit paranthesis for default ctor
Message m = new Message(sFrom, sTo) {Subject="Whatever"}; // parameterized ctor followed by property setter

Object initializers are essential when dealing with anonymous types / in LINQ. The following line creates a new instance of an anon type with From, To and Subject properties

var newMessage = new {From="F", To="T", Subject="Whatever"};

For more on this, refer to this MSDN page - Object and Collection Initializers

However object initializers require properties to be public and consequently the underlying types to be mutable. It is generally preferred to have "immutable" (once created, the value of the object doesn't change) data structures to prevent side-effects or accidental modification. Maybe that's the point Jon was trying to make... I dont have the 2nd ed.

Gishu
Immutability is the big point I'm trying to make in that section, yes. There are other benefits to getting all the information in one go though.
Jon Skeet
+4  A: 

This code:

Message message = new Message(
"[email protected]",
"[email protected]",
"I hope you like the second edition")
{
       Subject = "A quick message"
};

is equivalent to this:

Message tmp = new Message("[email protected]", 
    "[email protected]",
    "I hope you like the second edition");
tmp.Subject = "A quick message";
Message message = tmp;

That's just object initializer syntax: see chapter 8 for more details.

The problems with this are:

  • It's not clear what all the string arguments mean - what's "from", what's "to", what's the body etc
  • It requires the type to be mutable (unfortunate for all kinds of reasons)
  • If you want to also specify the subject in the constructor, you end up with a bunch of different overloads
  • If you have cross-validation between (say) subject and body, you need to be careful about when you do it

With optional parameters and named arguments, all of this is solved:

// The argument names may be wrong here; I don't have the book with me.
// Intellisense will prompt you though :)
Message message = new Message(
    from: "[email protected]",
    to: "[email protected]",
    body: "I hope you like the second edition",
    subject: "A quick message);

It's clear what means what, it's all in a constructor call so the type can be immutable, you can have a single constructor with optional parameters (e.g. here we could have a byte[] attachment = null parameter specified in the constructor), and you can do all the validation in one place. Lovely.

Jon Skeet
don't you love it when the author --and the biggest celebrity in c# and SO communities-- himself answers the question. I am flattered.
vehomzzz
You think *you* love it - I love having my writing discussed :)
Jon Skeet