Thursday, November 6, 2008

C# Signatures

On a thread in the Visual Studio 2010 C# and VB Feedback forum, DMeglio posted a question about whether C# 4.0 could be extended to support extended generic constraints.

I'm just curious, is the feature set for C# 4.0 locked? There is one thing that I feel is a glaring omission, and really hurts C#. The fact that generics do not support operator constraints. This is a huge issue for many of us. Why can't we do:

public class List<K> where operator+

I know this would make my life easier, I guess I'm just wondering if it's definitely been tabled or if it's still a possibility for 4.0

So I thought about this for a bit and proposed something similar to the C++ signature abstraction or a Haskell Type Class.

Nominative vs. Structural Typing

Consider the following types.

public class Cat
{
    void Speak() { Console.WriteLine("Meow!"); }
}

public class Dog
{
    void Speak() { Console.WriteLine("Woof!"); }
}

Well, they both have a Speak() method but they do not implement any common interfaces or inherit from a common type (besides Object).  If we want to call Speak() polymorphically on Cat and Dog then we could modify them to implement an ISpeakable interface or Animal abstract base class.

That's because the CLR uses Nominative Typing.  Two types are related only in the ways they explicitly declare as part of their definition.  We take this for granted every day, but it's not the only way to do things.  There's also Structural Typing.

The Cat and Dog classes obviously share structural similarities even if they don't declare them.  They both have Speak methods...

C# Signature Proposal

Consider the following pseudo-code.

public signature Numeric<T>
{
    static T operator+(T left, T right);
    static T Zero { get; }
}

Any type can be said to satisfy this signature if it has the specified members.  It need not actually declare that is satisfies the signature.

Assuming this notation, we can define methods like the following:

public static class Math
{
    public static T Sum(IEnumerable<T> values)
        where T : Numeric<T> // signifying conformance to a signature, NOT inheritance
    {
        T total = T.Zero; // the type must have a Zero property, per the signature
        foreach (T value in values)
            total += value; // valid because the type has an operator+, per the signature
       
return total;
    }
}

Intuitively, the Sum method can be used on any type that supports all of the Numeric<T> operations.

Ok, but Int32 does not actually have operator+, or Zero defined on it.  So those methods must come from somewhere else!  Some of them could be defined as a default implementation provided by the signature but that's not enough.

C# Extension Properties and Static Methods

In C# 3.0, we got some fancy compiler syntax for extension methods.  They are defined like this:

public static class EnumerableExtensions
{
    public static int Count<T>(this IEnumerable<T> values)
    {
        int count = 0;
        foreach (T value in values)
            count += 1;
        return count;
    }
}

This is all well and good but there is no syntax for extension properties and extension events, or for static extension methods, et. al.

It turns out that the current syntax for extension methods is very awkward to extend.  Where will you insert this in those extension property and event declarations?

C# Signature Extension Proposal

Ah!  But what if we allow signatures to extend one another or to extend existing types?

Then we can define new behaviors on those signatures that will apply to any types that satisfy the signature.  If the signature extends another signature then it incorporates all parts of that other signature.  Likewise if it extends a type then it takes on all aspects of that type.

But the compiler could also suppose that if a type conforms to a signature that is in scope, then all members of that signature can be used implicitly as if they were members of that type.  Just like extension methods.

public signature Int32Extensions : Int32, Numeric<Int32>
{
    public static Int32 Zero
    {
        get { return 0; }
    }

    public static Int32 operator+ (Int32 a, Int32 b)
    {
        return a + b;
    }
}

Voila!  Static extension methods and properties.

How about non-static extension methods and properties?

public signature Int32Extensions : Int32
{
    // I'm an extension property of Int32!
    public bool IsZero
    {
        return this == 0;
    }
}

Simplifications

If all we want is support for things like extension properties then it's clear that we can simplify the proposal greatly.  Instead of defining something new like a signature we could define something like an extension class.  However I feel that the structural typing ideas are quite useful on their own.

3 comments:

Unknown said...

The Cat and Dog example with Speak method is now supported in c# 4 (by using dynamic keyword)

Basically, it saves you from writing reflection based code. If the method doesn't exist, it will throw an exception at runtime.

I saw this in 1 of the videos by Anders H on channel9

They call it duck typing in dynamic languages.

Jeff Brown said...

@kalpesh
I'm aware of the "dynamic" type since I attended Anders talk at the PDC.

I'm strictly talking about static typing considerations here.

David Nelson said...

This is an interesting proposal. How do you see your idea of an "extension class" fitting in with the .NET type system? Would a wrapper class have to be created which inherits from the specified base class or implements the specified interface? How would that affect reference equality?