Skip to main content

Posts

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...

Factoring Out Common Patterns in Libraries

A well designed core library is essential for building concise, maintainable programs in any programming language. There are many common, recurrent patterns when writing code, and ideally, these recurring uses should be factored into their own abstractions that are distributed as widely as possible throughout the core library. Consider for instance, an "encapsulated value" pattern: /// <summary> /// A read-only reference to a value. /// </summary> /// <typeparam name="T">The type of the encapsulated value.</typeparam> public interface IValue<T> { /// <summary> /// A read-only reference to a value. /// </summary> T Value { get; } } This shows up everywhere, like Nullable<T> , Lazy<T> , and Task<T> (property called "Result"), IEnumerator<T> (property called "Current"), and many many more. However, the common interface of a value encapsulated in an object has not been factored o...

High-level constructs for low-level C: exception handling, RAII, sum types and pattern matching

There are numerous high-level abstractions available in other languages that simply make programming easier and less error prone. For instance, automatic memory management, pattern matching, exceptions, higher order functions, and so on. Each of these features enable the developer to reason about program behaviour at a higher level, and factor out common behaviour into separate but composable units. For fun, I've create a few small macro headers that enable some of these patterns in pure C. If anyone sees any portability issues, please let me know! libex: Exception Handling and RAII RAII in C is definitely possible via a well-known pattern used everywhere in the Linux kernel . It's a great way to organize code, but the program logic and finalization and error logic are not syntactically apparent. You have to interpret the surrounding context to identify the error conditions, and when and how finalization is triggered. To address this, I encapsulated this RAII pattern in a macro...

CLR: Verification for Runtime Code Generation

The CLR's lightweight code generation via DynamicMethod is pretty useful, but it's sometimes difficult to debug the generated code and ensure that it verifies. In order to verify generated code, you must save the dynamic assembly to disk and run the peverify.exe tool on it, but DynamicMethod does not have any means to do so. In order to save the assembly, there's a more laborious process of creating dynamic assemblies, modules and types, and then finally adding a method to said type. This is further complicated by the fact that a MethodBuilder and DynamicMethod don't share any common interfaces or base types for generating IL, despite both of them supporting a GetILGenerator() method . This difficulty in switching between saved codegen and pure runtime codegen led me to add a CodeGen class to Sasa, which can generate code for either case based on a bool parameter. Since no common interface is available for code generation, it also accepts a delegate to which it dispa...

Peirce's Criterion: command-line tool

I've written a simple command-line tool filter out statistical outliers using the rigourous Peirce's Criterion . The algorithm has been available in Sasa for awhile, and will be in the forthcoming v0.9.3 release. I've also packaged the command-line tool binary for running Peirce's Criterion over multi-column CSV files (LGPL source available here ).