A site devoted to discussing techniques that promote quality and ethical practices in software development.

Tuesday, May 13, 2014

CLR and Mono Runtime difference - System.Diagnostics.DefaultTraceListener.AssertUiEnabled

This one to some is a very contentious issue and is present in the Mono runtime running in Mint-15.

While this property is not well known to many as rarely one would need to touch this in CLR, it is intimately related to the well-known method System.Diagnostics.Debug.Assert().

The runtime behaviour of Debug.Assert() depends on the behaviour of the trace listener(s) that have been loaded at that time. When the expression becomes false, Debug.Assert() calls the System.Diagnostics.TraceListener.Fail().

At start up time, CLR & Mono would load a number of System.Diagnostics.TraceListener-derived class(es). If there is no overriding specification in the application's config file, the runtime loads the System.Diagnostics.DefaultTraceListener and is identified in the collection of TraceListeners by the name "Default".
In CLR for most runtime environment, such as Console, WinForm, WPF, WCF, Debug.Assert() by default will alert the user with a user-interface that allows the user to abort or ignore. This behaviour has not changed since the first release of the .Net framework and runtime. Of course this behaviour is entirely configurable.

If System.Diagnostics.DefaultTraceListener is the default TraceListener, the default behavour of alerting the developer is by means of a user-interface to inform of the unmet condition. This is the desired behaviour for most situations during development. This is because the System.Diagnostics.DefaultTraceListener.AssertUiEnabled is default to true.

However, in Mono, the System.Diagnostics.DefaultTraceListener.AssertUiEnabled is by default initialized (or lack of explicit initialization in DefaultTraceListener class) to false.

This discrepancy in the default value often leads to developer's gripe and  incorrectly accusing the Mono's System.Diagnostics.Debug.Assert() failure to catch the unmet condition; by defaut Mono just does not alert the user loudly. The Internet has plenty of Linux/Unix ways of 'fixing' this problem. But I will present here the .Net ways of fixing this discrepancy in the spirit of maintaining cross-platform runtime consistency.

It is nothing more annoying when one writes defensive code using Debug.Assert() liberally only to be silently scuttled by a difference in default value in another class. I have lost count of the number of hours trying to find some problems that should have been caught by Debug.Assert() but flew past me silently!

How to fix this?

To convince yourself you can report out the default value for DefaultTraceListener.AssertUiEnabled by writing a simple console application like this that can run successfully in both Mono and CLR:

class MainClass
  public static void Main (string[] args)
    Console.WriteLine ("Default value of AssertUiEnabled = {0}",
      (Debug.Listeners ["Default"] as DefaultTraceListener).AssertUiEnabled);

You should get true when run in CLR and false when in Mono.

The reason for assuming false in Mono could be historical where Mono initially did not have any GUI support; this has changed and the code for DefaultTraceListener.Fail() contains code to invoke user-interface.

However, even in the absence of rich user-interface it should adopt the approach used by other languages, such as Java's assert keyword, assert() in C/C++ language, where it aborts the execution reporting the point of failure. Not reporting to a developer loudly by default is dangerous, considering the usage promoted by Debug.Assert(). If a crude way of alerting the user is unsuitable, the .Net has ways to allow user to alter the behaviour and that is a user-initiated process and that the user then know where to look for violations. This also makes the runtime behaviour consistent with CLR. Not telling misleads the developers of fault. The current situation is like asking Java developers to make the JRE's behaviour of java -ea different in Windows and in Linux!

Without recompilation - use Application Configuration File

This is by far the most convenient way to fix this problem and that it works for both CLR and Mono.

You simply include the following fragment in your application configuration (if none, create one) to add an assert element to force the assertuienabled to true:

       <!-- This changes the DefaultTraceListener.AssertUiEnabled from false to true -->
       <assert assertuienabled="true" />

With code

This approach will require you to compile new code. However, if you are testing ready-made assembly and do not want to rebuild them, this approach can be adopted by including the following piece of code in the start up code:
(Debug.Listeners ["Default"] as DefaultTraceListener).AssertUiEnabled = true;

I hope this post will make the experience of developers looking for Mono as their cross-platform environment more pleasing.

CLR and Mono Runtime difference - XmlSerializer for read-only auto-property

This is one of a number of posts to highlight runtime difference between Mono and CLR/.Net. It is not a criticism of the good works of the Mono team but to highlight the differences so that developer interested in using Mono as a cross platform development platform, like me, is aware of them and to take necessary avoidance strategy.

Of course, in a perfect world, there shouldn't be any runtime difference and let's hope these posts are of transient nature.

This post draws reader's attention to the difference of the runtime behaviour of  System.Xml.Serialization.XmlSerializer in Mono and in CLR. 

In CLR, if the serializer is presented with a class that has read-only auto-property, the runtime will throw an exception, System.InvalidOperationException, whose origin can be traced to the sgen.exe. However, when the same piece of IL code is executed in Mono (without compilation), there is no exception and in fact Mono would blissfully serialize/deserialize those read-only auto-properties, which is clearly wrong.

This runtime discrepancy only arises only if you use read-only auto-property like this:

public class Sample
   public String Name { get; private set; }
   // ....

Mono can handle any other forms of read-only property constructs.

Blog Archive