Skip to content

Delegates Gotchas

Delegates are one of the first and most recognizable features of .net
framework. A delegate type can represent any method with a compatible
signature. They are so ubiquitous, that I can hardly imagine any .net
software written without them. Despite the popularity, there are
several overlooked features that can be source of subtle and difficult
to find bugs. I would like to dedicate this post to bring some light
and explain one of those pitfalls.

Let’s start from a puzzle. What do you think will be printed in the
next program?

   1: public class Program
   2: {
   3:     private static void Main(string[] args)
   4:     {
   5:         Action<int> action = x => Console.WriteLine("A {0}", x + 10);
   6:         action += x => Console.WriteLine("B {0}", x + 20);
   7:         Console.WriteLine("----(1)----");
   8:         action(10);
   9:         ModifyAction(action);
  10:         Console.WriteLine("----(3)----");
  11:         action(10);
  12:         Console.ReadLine();
  13:     }
  14:
  15:     private static void ModifyAction(Action<int> action)
  16:     {
  17:         action += x => Console.WriteLine("C {0}",x + 30);
  18:         Console.WriteLine("----(2) ----");
  19:         action(10);
  20:     }
  21: }

And the answer might be surprising:

—- (1) —-

A 20

B 30

—- (2) —-

A 20

B 30

C 40

—- (3) —-

A 20

B 30

I would expect that lines after (2) and after (3) will be the
same. What do you think could go wrong? Using method ModifyAction
looks like reasonably safe thing to do: Action delegate is a reference
type, so passing it to the method shall pass the reference. Operator
+= shall translate into Combine method call … What just happened
here?

The key to understanding the problem is Delegates Immutability. Type
Immutability is a strong term, which means that instance of that type
is an object whose state cannot be modified after it is created.

System.Delegate class is immutable class; once created, the
invocation list of a delegate does not change. Operations, such as
Combine and Remove, do not alter existing delegates. Instead, such an
operation returns a new delegate that contains the results of the
operation, an unchanged delegate.

So although the ModifyAction has a reference to action object on the
stack, the reference itself is replaced as a side effect of +=
operator (call to Combine method).

   1: private static void ModifyAction(Action<int> action)
   2: {
   3:             action += x => Console.WriteLine("C {0}",x + 30);

After we understood the reason for test failure, the trivial
solution for the problem would be an addition of ref classifier to method arguments.

   1: private static void ModifyAction(ref Action<int> action)
   2: {
   3:             action += x => Console.WriteLine("C {0}",x + 30);

This is an uncommon situation when ref appeared to be useful for
passing reference types. This allows called methods to modify the
object to which the reference refers because the reference itself is
being passed by reference.

Concept of immutability is very powerful, and usually
common to multi threaded environment. It requires a deep understanding
of what is going on behind the scenes and may cause subtle and
difficult bugs. Although current latest version of c# compiler does
not warn about this mistake, some tools like Resharper 4.x can spot
dangerous behavior. I hope that by writing this post I saved long bug
hunting session for someone.

Technorati tags: , ,
Tagged , ,

A Breath of Fresh Doxygen for Caliburn

Yesterday I added a Doxygen configuration to the Caliburn project. The intention was to make it easier to generate or update project documentation. Please notice that output formats are set to html and compiled help (chm).

Let me introduce the Doxygen ,If you haven’t used it before. Doxygen is a well known and de facto standard documentation tool for open source projects. It has many amazing features, for example:

  • It requires very little overhead from the writer of the documentation. Plain text will do, but for more fancy or structured output HTML tags and/or some of doxygen’s special commands can be used.
  • It supports C/C++, Java, (Corba and Microsoft) Java, Python, IDL, C#, Objective-C and to some extent D and PHP sources.
  • Supports documenting of files, namespaces, packages, classes, structs, unions, templates, variables, functions, typedefs, enums and defines.
  • Automatically generates class and collaboration diagrams in HTML (as clickable image maps) and LaTeX (as Encapsulated PostScript images).
  • Uses the dot tool of the Graphviz tool kit to generate include dependency graphs, collaboration diagrams, call graphs, directory structure graphs, and graphical class hierarchy graphs.
  • Generates a list of all members of a class (including any inherited members) along with their protection level.
  • References to base/super classes and inherited/overridden members are generated automatically.
  • Includes a fast, rank based search engine to search for strings or words in the class and member documentation.
  • Allows automatic cross-referencing of (documented) entities with their definition in the source code.
  • All source code fragments are syntax highlighted for ease of reading.
  • Can cope with large projects easily.

You can download this free and open source software from doxygen.org site.

On the image below you can see a small snippet from class diagram.

class

The next image shows a graphic display of the project directories tree.

directories

Here you can see the highlighted syntax and cross referenced code.

code

On the last image you can see the call graph for one of the methods

call_graph

I hope that this configuration will make it easier to understand and start using the Caliburn framework.

Today’s WTF: Graphviz installation wizard

Today’s WTF will be about installation wizard annoyances. Yesterday, during installation of Graphviz, I came across this funny example:

graphviz_wtf

As you can see the dialog can not be resized, and you can only guess that there is an OK button on the right.

Tagged

Reading chm files with ‘#’ character in the file name.

One of the most annoying things I hate in chm files, is the fact that you can not read this file if it has a # character in the file name.

In the image bellow you can clearly see that application fails to render the text of the book.
The file name was C# Cookbook, 2nd Edition (Cookbooks (O’Reilly))#AUTHORS#Jay Hilyard#ISBN#0596100639#LIST##TAGS#.chm

This bug is old and well known, but not yet fixed in windows XP. I guess the system which renders
the text confused by # since it used as an an anchor sign to bookmark on the page.

I would like to introduce my solution to this annoying problem: CHM Reader for Firefox. This is nice and small plugin which can be downloaded from Firefox Add-ons page.
It is installable with one click and will be updated automatically if a newer version available.

Usage is very simple: File Open chm files

Please notice that you can use all your standard Firefox habits in order to navigate between tabs and search within the page.

Is Constructor Thread Safe? What do you think?

Level 2
Several days ago, one of my colleague asked me this question. My first impulse was to answer no, but then I thought that the answer was not obvious. So I wrote a short example and played a little with ILDASM.
Imagine that we have next definition for class CTest
   1: namespace ConsoleApplication1
   2: {
   3:     class CTest
   4:     { 
   5:         public CTest(int i) {}
   6:     }
   7: }

I think that first confusing thing is the usage of the new operator. It may give you a feeling that something here is different. Take a look at the line 7 of this example. What do you think, is this method is thread safe?

   1: class C
   2: {
   3:     private CTest c;
   4:  
   5:     public void Foo()
   6:     {
   7:         c = new CTest(1);
   8:     }
   9: }

This is what happens behind the stage in method Foo(). Here is the Foo() code in a little details

1 .method public hidebysig instance void Foo() cil managed
2 {
3 .maxstack 8
4 L_0000: nop
5 L_0001: ldarg.0
6 L_0002: ldc.i4.1
7 L_0003: newobj instance void ConsoleApplication1.CTest::.ctor(int32)
8 L_0008: stfld class ConsoleApplication1.CTest ConsoleApplication1.CTest::c
9 L_000d: ret
10 }

It is clear that line 7 with opcode newobj creates and pushes a new instance of CTest into the stack and exactly one line later, the local variable c is assigned with a brand new value. If multiple threads were calling CTest::Foo() the result would be unpredictable.

We need to consider one more subtle issue: constructor parameters. If one of the parameters is a reference type, it means that external thread may change the referenced object and make the constructor invalid.

   1: class Test
   2: {
   3:     public Test(IList items)
   4:     {
   5:         if(items.Count > 0)
   6:         {
   7:             // do something special
   8:         }
   9:     }
  10: }


Conclusion:

Constructor is not an exception case then we deal with multi threaded environment. I have no idea why and how this simple issue can confuse anyone but since I witnessed a long discussion regarding this issue, I contribute this post to remove any kind of hesitations. Enjoy.

Byzantine failures

Yesterday I had a conversation with my colleague at work regarding impossibility of capturing the system state in the presence of message losses. I quoted Nancy Lynch book and talked about half an hour about Byzantine failures.

Imagine my surprise that first thing I saw today in the Dr.Dobb’s web portal  is an article about Byzantine Generals. What a small world! Is it a global conspiracy? Big brother is watching.

dos2unix as ^M solution in Git pre-commit hook

Apparently this problem is well known and common
solution is to comment out next lines in the
.git/hooks/pre-commit file.

p.two{border-style: solid;border-width: thin}p.name {background-color: rgb(240,240,2

1 if (/\\s$/)
2 {
3 bad_line(trailing whitespace, $_);
4 }

I personally don’t like this approach; instead i will follow
make your compiler happy” advice. Small unix utility dos2unix was created to solve exactly this type
of problems. All i need to do is to add this utility to pre-commit hook and I hope it will do the magic.

First WTF with new Git repository

First check-in brings first surprises: git complains about suspicious trailing white spaces.
Apparently the usual M$oft ^M by the end of the line makes it crazy. I do understand
that hidden garbage in the file is wrong, but what do I do now?

Switching to Git

I am going to try the GitHub service. Good bye Subversion and TortoiseSvn!
Now my life is going to be much easier :)

My Library and Goole books search

I would like to recommend the Google Books Search service, for those who wants to organize large collection of books.
It supports custom collections of items, labels and reviews, allowing you to define and manage
your own library. In my opinion it’s great to be able to search your own books from any computer and to group them as you need.

I have published the several hundreds of my books (less then 10% ). Please take a look. If you want to share and exchange please leave me a message