About Jolt.NET Libraries

Inspired by the Boost C++ libraries, Jolt.NET aims to complement the .NET Base Class Library (BCL) with algorithms, data structures, and general productivity tools. It is the hope of the authors that the features of Jolt.NET will one day be part of, or represented in the BCL and the .NET Framework.

ProxyTypeBuilder Usability Issue

While working on implementing utilities to parse and read an XML doc comment file, I came across the need to abstract the file system for the purpose of testing.  This was a perfect time to use the Jolt.Testing library and generate an assembly with a proxy and interface to the static System.IO.File class!  My intent was to write the following code.

using Rhino.Mocks;
using Jolt.Testing.Generated.System.IO;
using System.IO;

void FileInteractions()
IFile fileProxy = Mocker.Current.CreateMock<IFile>();

Stream fileContents = new MemoryStream(/* stream data */);

FileReader reader = new FileReader(fileProxy);

This is the example I use in my documentation (creating the IFile interface), and was the prime motivation for creating the Jolt.Testing library.  In this test, the file system is never accessed and the IO operation (Open) happens in memory.  However, there is a fundamental problem with this code – it won’t compile!  Can you see why?

When I saw the compilation error, my heart sank.  The Open method returns a FileStream object, not a Stream object (the downcast is not guaranteed to work)!  All of a sudden I realized that generating an abstraction to the System.IO.File class accomplished very little since using the Open method still requires that you use the file system.  Sure, I could use the OpenText method which returns a StreamReader that is wired to my memory stream (and I ultimately did for this test), but there is still a fundamental problem with the usability of the ProxyTypeBuilder outputs:

A generated interface contains method signatures with concrete types that are intended to be abstracted by the interface.

If you think about it, you would never design a base class to a hierarchy and make references to the concrete types within the base class.  Doing so defeats the purpose of creating the base class all together!  The same rationale applies to an interface that generalizes some kind of functionality.  Recall the wisdom from the GoF: when possible, code against an abstraction, not a concrete implementation.

At this point, I thought my implementation was all for naught.  When the shock subsided, I realized that there is flexible solution to the problem, made easy-to-implement by the modularization and design of the ProxyTypeBuilder class.  The idea to the fix is as follows.  For the ProxyTypeBuilder methods AddMethod and AddProperty (entities that return a value), I will need to add an overload that accepts an override type for the return value.  The functions will validate to the make sure that the given type is indeed a base type of the overridden type prior to generating any code.  When the generated code is executed and the real subject type returns its object, the proxy will return a reference to the object’s base type, which hides the concrete type, and everything works as expected.

The pros to this solution:

  • Option to override is flexible, avoiding the incorrect auto-conversion approach.
  • It makes sense to change the return value of FileStream to Stream, but it doesn’t make sense to change DateTime to ValueType.
  • Solution extends easily to XML configuration of ProxyAssemblyBuilder.

The cons to this solution:

  • Xml documentation for the return value may be incorrect; it may still refer to a concrete type after overriding.
  • Generated assemblies for the same type are generally incompatible; you can’t swap one with another as the signature of some methods may be different.
  • Developers may have needed a real reference to the concrete type, and so a downcast is required.
  • Can’t apply the same idea to method parameters since functions called from the parameters may not exist in the base type.

Apart from the parameter issue that requires investigation, my feeling is that the cons to the solution are negligible.  In any case, do let me know what you think.  I plan to start work on this feature after the Jolt 0.2 release.

More on XML Documentation Comments

I recently posted about some of the challenges involved with implementing an algorithm that will locate an XML doc comment file, given a reference to a System.Reflection.Assembly object.  Today, I would like to discuss the extent of how this feature will be used and exposed in the Jolt library.

Initially, I had planned to keep the XML doc comment parsing internal and expose it as a feature of the ProxyTypeBuilder class.  As described in work item #95, copying existing XML doc comments to those of the generated interface and proxy type will provide richer Intellisense.  However, while designing the classes that implement this feature, I noticed that they would be better suited as public types as they may be used to solve many XML doc comment parsing tasks.  Consequently, the following use cases will be supported.

  • Inferring the location of an XML doc comment file from a reference to a System.Reflection.Assembly object.
  • Obtaining the XML doc comments for a given metadata type (i.e. System.Type, System.Reflection.MethodInfo, System.Reflection.ConstructorInfo, etc…).
  • Converting a given metadata type into its XML doc comment string representation.

The code example in the previous post on this topic gives the syntax example for the first two bullets.  The conversion task allows one to take a MethodInfo type for a method such as void Namespace.MyType.MyMethod<U>(out T t, U u[]) and turn it into the string “M:Namespace.MyType`0.MyMethod(`0,``0[])”, which is the key into the XML doc comment data for the corresponding method.

If you search the web for articles relating to reading or parsing an XML doc comment file, you will see many requests for knowledge on how to transform a .NET metadata type into the corresponding XML documentation.  The proposed XmlDocCommentReader class will make this very easy to do.  The conversion functions are geared more towards lower-level development, and they may be used to support the implementation of an XSLT or various XPath queries.

These features are currently under development and will be ready within a few days (of development time).  Currently, I’m focusing on the testing of all of the possible permutations of generic/array/pointer/ref types that change the resulting key into the XML doc comment member list.  There are plenty of permutations, and a lot more than I had initially expected!