Skip to main content

Posts

ThreadScoped<T> The Next Generation

Jeroen Frijters helpfully pointed out that the CLR implements some hard limits on nesting generics, which is 99 for .NET 4 based on my tests. My previous implementation of ThreadScoped<T> was thus limited to 99 instances. Not very useful! The solution is actually quite simple, which I briefly outlined on Jeroen's blog: add more type parameters and use a simple base-99 counting scheme to generate new instances. Each additional type parameters thus increases the permutations 99 fold. One type index parameter yields 99 1 instances, two type index parameters yields 99 2 instances, three type index parameters yields 99 3 , and so on. No one in the foreseeable future will require more than 99 3 , which is almost a million thread-local variables, so I've added two more type index parameters to make Ref<T0, T1, T2> . The instance allocation function is now: internal override ThreadScoped<T> Allocate() { // If 'next' is null, we are at the end of th...

Faster Thread-Local Data with ThreadScoped<T>

Awhile ago, Jeroen Frijters blogged about .NET 4's new ThreadLocal<T>, and how it was implemented. It was based on a neat generics trick exploiting the fact that the CLR does not erase types. Indexing a generic type X with a type T, means X<string> has distinct static and thread-local fields from say, X<int>. I've actually used this trick before to implement a type of safe reflection. Jeroen's sample implementation exploiting this trick for thread-local instance variables seemed far too complicated however, and it suffered from a number of limitations that he notes in his post. If Microsoft's implementation was even more complicated as was claimed, I wasn't confident it would perform very well at all. I decided to do my own implementation, without conforming the ThreadLocal<T>'s interface since I have very specific applications in mind. ThreadScoped<T> As I suspected, my implementation was considerably simpler , coming in a...

Idioms in C# with LINQ

There's a great post on implementing idioms with LINQ, and the example application was to implement formlets, as WebSharper does for F#. Tomas's post is well written, so if you're unclear on the above concepts I recommend reading it first before proceeding with this article. The claim in that post is that idioms can only be encoded via LINQ's 'join' operators. While strictly true if you stick to all the LINQ rules, because LINQ queries are just naive syntactic transforms you don't have to follow the rules. You can thus exploit this to hijack the signatures for the SelectMany overloads to yield idiom signatures. It's not all sunshine and roses though, as there are consequences. Overview LINQ is a standard set of methods one can implement that the C# compiler can use to provide "query patterns". This query: var foo = from x in SomeFoo from y in foo.Values select y; is translated by the C# compiler to: var foo = Some...

IObservable<T> and Delegate Equality

Equality and identity are often intermingled in the .NET framework. .NET delegates correctly implement a straightforward structural equality , where if two delegates are equal if they designate the same method and the same object, regardless of whether the delegate is a unique instance: class Bar { public void Foo(int i) { } } var bar = new Bar(); Action<int> a1 = bar.Foo; Action<int> a2 = bar.Foo; Console.WriteLine("Delegate Equality: {0}", a1 == a2); // prints: // Delegate Equality: True However, an IObservable<T> created from delegates does not respect structural equality, and reverts to an identity criterion: // use a1 and a2 from previous code sample var o1 = Observer.Create<int>(a1); var o2 = Observer.Create<int>(a2); Console.WriteLine("Observable Equality: {0}", o1 == o2 || o1.Equals(o2) || EqualityComparer<IObserver<int>>.Default.Equals(o1, o2)); //prints: // Obs...

Open Instance Delegate for Generic Interface Methods

Ran into a snag when developing the latest abstraction for Sasa. The problem is distilled to its simplest form in this Stack Overflow question. In summary, while the CLR supports open instance delegates to interface methods , and supports delegates to generic interface methods, it does not seem to support the composition of the two, ie. an open instance delegate to a generic interface method. The following trivial example fails when creating the delegate with a NotSupportedException: interface IFoo { void Bar<T>(T j); } class Foo : IFoo { public void Bar<T>(T j) { } } static void Main(string[] args) { var bar = typeof(IFoo).GetMethod("Bar") .MakeGenericMethod(typeof(int)); var x = Delegate.CreateDelegate(typeof(Action<IFoo, int>), null, bar); } However, the CLR does support open instance delegates to generic class methods. For some reason interfaces are singled out here, and it...

Sasa v0.9.3 Released!

I recently realized that it's been over a year since I last put out a stable Sasa release . Sasa is in production use in a number of applications, but the stable releases on Sourceforge have lagged somewhat, and a number of fixes and enhancements have been added since v0.9.2. So I decided to simply exclude the experimental and broken abstractions and push out a new release so others could benefit from everything Sasa v0.9.3 has to offer. The changelog contains a full list of changes, too numerous to count. I'll list here a few of the highlights. IL Rewriter C# unfortunately forbids certain types from being used as generic type constraints, even though these constraints are available to CIL. For instance, the following is legal CIL but illegal in C#: public void Foo<T>(T value) where T : Delegate { ... } Sasa now provides a solution for this using its ilrewrite tool. The above simply uses the Sasa.TypeConstraint<T> in the type constraint and the rewriter will ...

Abstracting Computation: Arrows in C#

I just committed an implementation of Arrows to my open source Sasa library . It's in its own dll and namespace, Sasa.Arrow, so it doesn't pollute the other production quality code. The implementation is pretty straightforward, and it also supports C#'s monadic query pattern, also known as LINQ. It basically boils down to implementing combinators on delegates, like Func<T, R>. It's not possible to implement the query pattern as extension methods for Func<T, R> because type inference fails for even the simplest of cases. So instead I wrapped Func<T, R> in a struct Arrow<T, R>, and implemented the query pattern as instance methods instead of extension methods. This removes a number of explicit type parameters that the inference engine struggles with, and type inference now succeeds. Of course, type inference still fails when calling Arrow.Return() on a static method, but this is a common and annoying failure of C#'s type inference [1]. What i...