Vivek's profileA Developer's ExperiencePhotosBlogListsMore ![]() | Help |
A Developer's ExperienceAn 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. |
||||||
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():-
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 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 MethodSanjeev and I have posted an article at CodeProject – Template 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. 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
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. |
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.
Public folders
|
|||||
|
|