Daniel Earwicker Chief Software Architect
CNL Software Ltd

Using pointer syntax as a shorthand for IEnumerable


ROSLYN 2014-04-26

Another quickie extension to C#. In the current language, a type declaration T! is shorthand for Nullable.

But equally important in modern C# programs are sequences of values, so a similar shorthand for IEnumerable would be ideal. The asterisk symbol is underused (you can suffix a type with asterisk to make a pointer, but only in unsafe contexts), and this was the choice made by the intriguing research language Cω that influenced LINQ, so let's copy that:

int* numbers = new[] { 1, 6, 55, 4, 11 };

foreach (var n in numbers)
    Console.WriteLine(n);

In Binder_Symbols.cs we find:

case SyntaxKind.PointerType:
    {
        var node = (PointerTypeSyntax)syntax;            
        ReportUnsafeIfNotAllowed(node, diagnostics);
        
        var elementType = BindType(node.ElementType, diagnostics, basesBeingResolved);
        if (elementType.IsManagedType)
        {
            // "Cannot take the address of, get the size of, or declare a pointer to a managed type ('{0}')"
            Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, elementType);
        }

        return new PointerTypeSymbol(elementType);
    }

The call ReportUnsafeIfNotAllowed is what checks for the unsafe context. So I commented that out and added my own check for not-unsafe, before doing something very similar to what happens for T? -> Nullable elsewhere in the same file:

case SyntaxKind.PointerType:
    {
        var node = (PointerTypeSyntax)syntax;
        
        //ReportUnsafeIfNotAllowed(node, diagnostics);
        if (this.IsIndirectlyInIterator || !this.InUnsafeRegion)
        {
            NamedTypeSymbol enumerableT = GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T, diagnostics, syntax);
            TypeSymbol typeArgument = BindType(node.ElementType, diagnostics, basesBeingResolved);
            NamedTypeSymbol constructedType = enumerableT.Construct(typeArgument);
            if (ShouldCheckConstraints)
            {
                constructedType.CheckConstraints(this.Compilation, this.Conversions, syntax.Location, diagnostics);
            }
            return constructedType;
        }

        var elementType = BindType(node.ElementType, diagnostics, basesBeingResolved);
        if (elementType.IsManagedType)
        {
            // "Cannot take the address of, get the size of, or declare a pointer to a managed type ('{0}')"
            Error(diagnostics, ErrorCode.ERR_ManagedAddr, node, elementType);
        }

        return new PointerTypeSymbol(elementType);
    }

And we're done! We can now say things like:

static int *Squares(int *nums)
{
    return nums.Select(n => n * n);
}

Roslyn may not be very pretty - it's a hand-crafted top-down system, so it looks nothing like the "text book" functional parsers. But it's a real product as opposed to a clean example, so that's hardly surprising. Regardless, it is proving easy (even fun) to hack.

json-mobx - Like React, but for Data (Part 2) 2017-02-15
Redux in Pieces 2017-01-28
Box 'em! - Property references for TypeScript 2017-01-11
TypeScript - What's up with this? 2017-01-01
MobX - Like React, but for Data 2016-12-28
Eventless - XAML Flavoured 2016-12-24
Immuto - Epilogue 2016-12-20
Immuto - Radical Unification 2016-09-22
Immuto - Working with React (An Example) 2016-09-16
TypeScript - What is a class? 2016-09-11
Immuto - Strongly Typed Redux Composition 2016-09-11
TypeScript and runtime typing - EPISODE II 2016-09-10
TypeScript and runtime typing 2016-09-04
What's good about Redux 2016-07-24
TypeScript multicast functions 2016-03-13
Introducing doop 2016-03-08
TypeScript is not really a superset of JavaScript and that is a Good Thing 2015-07-11
A new kind of managed lvalue pointer 2014-04-27
Using pointer syntax as a shorthand for IEnumerable 2014-04-26
Adding crazily powerful operator overloading to C# 6 2014-04-23
Introducing Carota 2013-11-04
Want to comment on anything? Create an issue!