Vivek 的个人资料A Developer's Experience照片日志列表更多 工具 帮助

A Developer's Experience

An effective debugging technique is to explain your code to someone else. This will often cause you to explain the bug to yourself, followed by an embarrassed "Never mind. I see what's wrong". You can even use non-programmers as listeners.

Vivek

职业
地点
兴趣
I am Vivek Ragunathan. I am a Software Engineer in a leading software company. I have over 5 years of experience in the design and development of applications through VC++, MFC, ATL-COM, C#/.NET. I also have a fair amount of development experience in C++/CLI.

Over the few years of programming, I have developed immense interest in object oriented programming, interface/API design, writing generic/algorithmic/engine-sort-of code, infrastructure code development, operating system concepts and such. After learning .NET, my criticisms againt COM and MFC have become very vigorous.

Rhetoric Musings

正在加载...正在加载...

The Constraint Of Constraints !!!

I was happy programming with (generic) constraints which overtook the limitations in C++ templates. However, constraints need to be less restrictive. What is that? Let us say I want a helper method that checks a condition and throws an exception if the check failed. So that would be...

void TestCondition(bool condition, string msgText)
{
    if (!condition)
    {
        throw new Exception(msgText ?? "Unknown Error");
    }
}

I like it; it is cute. However, not at all times would the caller be happy with throwing System.Exception. Since the above method can be used in a wide variety of situations, it would make sense for the caller to specify the type of exception he would like to throw. It would be classic if the above is made generic taking type T and constraining it be to a derivate of System.Exception. Sounds great and so…

void TestCondition2<T>(bool condition, string msgText) where T : Exception
{
    if (!condition)
    {
        throw new T(msgText ?? "Unknown Error");
    }
}

The above code is dream still; it will result in a compilation error. Although generics offers the constraint that T should be a derivate of System.Exception, it does not relax it specifying the constructor it would like to use from T; in other words, there is constraint mandating T to expose a default constructor but none other. So we cannot offer the above facility with elegance (or performance?). There is the ugly way. How?

void TestCondition3(bool condition, Exception ex)
{
    if (!condition)
    {
        throw ex;
    }
}

Seems good? Partly No. If TestCondition2 was possible, the exception object(s) would be created only if the condition failed, while TestCondition3 meeting our purpose creates exception objects irrespective of the condition; and gets thrown if the condition fails.

So when are (generic) constraints going to be relaxed? C# 5.0?

System.Object – Reference or Value Type?

I was explaining about .NET types to this new guy in our team; new to the team and to .NET. I was explaining about reference and value types, allocation etc. And he asked, "Is System.Object reference type or value type?". Nice question, right? Let me add its corollary - Is System.ValueType a reference or value type?

CLR is the platform for loading types and executing code. All types in .NET are derivatives of System.Object. When we say System.Array is a reference type or System.Drawing.Point is a value type, it is an indication for the CLR to choose the allocation (heap or stack) and transport strategy for the Type. What I mean by transport strategy here is what gets copied on transport or assignment – the Type’s value(s) or its address.

For instance, what happens we write SomeType obj1 = obj2 or return SomeType():-

  • If SomeType is a reference type: It is the reference (or address to pointing to the object pointed to on the heap) that is copied to obj1. No new object is created. obj1 and obj2 point to the same object (on the heap). To create a new object (on the heap) based out of obj2, I must Clone().
  • If SomeType is a value type: It is the entire value of the obj2 that is copied to obj1 which is entirely a different object. So a new object (obj1) is created (on the stack) and a member wise copy is made from obj2 to obj1 where again the same rules apply.

I consider the transport strategy more important than where it is allocated. CLR could have all the locations entirely on the heap but still differentiate the Types based on the transport strategy. CLR chose to differentiate the types using both. CLR allocates a reference type on the heap and deals with such objects via references. A value type is allocated on the stack and always transports the entire content of the Type (what is considered its value).

So we as Type writers, indicate the allocation and transport strategy to the CLR by deriving from predefined Types. A Type derived from System.ValueType is (obviously) a value type (Stack\Value). A Type that is NOT derived from System.ValueType is a reference type (Heap\Reference). This is the model chosen by the CLR for dealing with any Type under the System.Object and System.ValueType in the object hierarchy. Nevertheless, all Types are derived from System.Object.

Now let us answer the real question. The Type's type is an indication for the CLR to determine how to treat the object. So that is for a Type I write. But if I create an (direct) instance of System.Object, how is it treated – allocation and transport strategies? For that matter, where would an instance of System.ValueType be allocated?

The quick answer is System.Object is a reference type, primarily because the CLR is a system driven by garbage collection. Besides, CLR does not require a special mechanism for reclaiming the objects allocated on the stack; a mere stack unwind is enough.

// o is allocated on the heap
System.Object o = new System.Object;

// Compilation Error! System.ValueType is an abstract class.
System.ValueType v = new System.ValueType();

I hope you see the end of chicken and egg story. Making System.ValueType abstract while allowing to create direct instances of System.Object is lot like the theory of God being the source of all creations. He (System.Object) is the beginning and end of everything.

Answering Ian - C++ Temporaries !!!

First, let us welcome Ian Halliday. Next let us answer his question.

Foo() returns a List object. But the List::Iterator iter(Foo()) declaration uses a reference to a temporary object, which would get obsolete even before the first iteration is complete. Typical C++ gotcha!

I have been bit hard with kind of stuff in my project a few times. Sanjeev and I have spent long hours thinking of devising a mechanism with which we can find out if a given C++ object is a temporary (actually we needed to prevent creating temporary objects of our class). Unfortunately our little brains could not find a solution.

So how do we fix Ian's problem? Unfortunate and simple - create a temporary only when you know you need it.


List lObject = Foo();
for (List::Iterator iter(lObject); !iter.AtEnd(); iter.MoveNext())
{
    DoStuff(iter.Current());
}


And hey make sure that List class is smart enough of making deep copies properly; else the above code will blow up again. Now let us wait to hear from Ian.

Mixing Design Patterns - Decorator Vs Template Method

Sanjeev and I have posted an article at CodeProjectTemplate Method Vs Decorator. Not many programmers realize the effect of mixing design patterns in use. This article is one such instance involving the Decorator and Template Method pattern. Hope you would enjoy the article. Read it. Rate it.

Article Excerpt:

This article is a result of the serendipity experienced when implementing a small framework. The framework had a bunch of classes, which implemented some of the widely used design patterns. One of the classes implemented the Template Method pattern. The situation then was to make that class extensible without modifying it. The Decorator pattern seemed the right fit to extend (decorate) the class.

Besides providing a level of sophistication in code and the fun in its use, design patterns do not reveal until asked for the problems in mixing them. This article explains the problems when mixing Decorator and Template Method patterns. The article also discusses the possible solutions to circumvent the problem in mixing the above design patterns. Know why these patterns don't gel well? Please read on.

Hot and interesting discussion is going on about the article. Don't miss it. And be sure to share your comments and thoughts.


Curious Case Of Anonymous Delegates !!!

Senthil has left us thrilled in his new post, and also inspired me to write about the topic. Although, anonymous delegates have become a mundane stuff amongst programmers, there is still these subtle stuff left unexplored. Alright, let us try to answer Senthil's question before he unravels the mystery in his next post.

A delegate is identified by its target. The target is the method to be executed on a delegate invocation and its associated instance or type. If the target is an instance method, the delegate preserves the target method pointer and the object instance. If the target is a static method, the delegate preserves the target method pointer and the type to which it belongs. So when a code like the one below to register a method to an event (or multicast delegate) is executed, a delegate object (EventHandler here) with the target information embedded is created and added to the invocation list of the event (or multicast delegate, KeyPressed here).

class SomeForm
{
	private Control control = new Control();

	public void OnFormLoad(object sender, EventArgs args)
	{
		control.KeyPressed += new EventHandler(OnKeyPressed);
	}
	
	// Rest of the code omitted to be succinct
};

Likewise, when unregistering the method handler, a new (EventHandler) delegate object is created with the same target information as above. As said earlier, a delegate is identified by its target. In other words, the Equals override on the delegate uses the target information for comparing two delegate objects. Hence in the following code that unregisters the method handler, the invocation list is searched for a delegate instance with the specified target information (Method: OnKeyPressed, Instance: SomeForm instance).

In the case of anonymous delegates, the compiler transforms the inline method code into a

  • static method, if the inline method code does not use any of the class's instance members or local variables or if it uses only the static members of the class.
  • instance method, if the inline method code uses at least one class member, any or no static members, and no local variables.
  • class with a method that represents the inline method code, if the inline method code uses local variables no matter whether it uses the class members or not.

Those might not be the extensive set of rules but sure are enough for our discussion. Given the following questionable code,

public EventHandler IfEnabledThenDo(EventHandler actualAction)
{
	return (sender, args) => { if (args.Control.Enabled) { actualAction(sender, args); } };
}

public void Initialize()
{
	control.KeyPressed += IfEnabledThenDo(control_KeyPressed);
}

public void Destroy()
{
	control.KeyPressed -= IfEnabledThenDo(control_KeyPressed);
}

we realize, without doubt, that the anonymous delegate (returned by IfEnabledThenDo) would be transported into a compiler generated anonymous class. Later when IfEnabledThenDo is called for registering\unregistering the method handler, an instance of anonymous class is created and the (EventHandler<Control.ControlEventArgs>) delegate is returned. And here lies the subtlety. Although the delegate from IfEnabledThenDo targets the method inside the anonymous class, the instance preserved as a part of the target information are different during registration and un-registration. In other words, the target method of the delegate returned by IfEnabledThenDo belong to different instances of the anonymous class. Hence the pretty code to unregister the (key pressed) method handler would not be actually unregistering since there would be a delegate previously registered in the invocation list of the (KeyPressed) event with the target instance same as the one used in the unregistration line of code. Very subtle!

Usually the hand written code tends to keep the registration and unregistration of the method handlers in the same class and so belong to the respective instances. Not so when you like watching the compiler magic.

Let us wait and see what Senthil says.

 
第 1 张,共 12 张
更多相册 (1)
Thanks for visiting. Your comments are most important. It will help me to keep the site and knowledge improving. Also please leave your email ID incase you want me to get back.
请稍候...
很抱歉,您输入的评论太长。请缩短您的评论。
您没有输入任何内容,请重试。
很抱歉,我们当前无法添加您的评论。请稍后重试。
若要添加评论,需要您的家长授予您相应权限。请求权限
您的家长禁用了评论功能。
很抱歉,我们当前无法删除您的评论。请稍后重试。
您已超过了一天之内允许提供的评论数上限。请在 24 小时后重试。
因为我们的系统表明您可能在向其他用户提供垃圾评论,您的帐户已禁用了评论功能。如果您认为我们错误地禁用了您的帐户,请联系 Windows Live 支持部门
完成下面的安全检查,您提供评论的过程才能完成。
您在安全检查中键入的字符必须与图片或音频中的字符一致。

Hoarding (BETA)

Sanjeev has launched his new SPACE.