|<<>>|40 of 275 Show listMobile Mode

New feature for C#: Anchored types

Published by marco on

I recently answered the question What features from other languages would you like to see in C#? by BatteriVolttas (Reddit)

I think Anchored Declarations and Qualified Anchored Declarations from Eiffel would be very useful.

I like the name “anchored” because you’re anchoring the type of one thing to another. Instead of using int throughout a class, you can just make e.g. a field named _id be an int and then make all other types (e.g. for the parameter passed to a method) refer to the anchor with like _id or typeof _id.

If the type of the field ever needs to change, you only need to update one place. It’s more expressive because the alternative is to explicitly write the type of the parameter, whereas that was never what was going on. The method doesn’t decide what the type is; we’re just used to _syncing_ it to the type of the field _manually_ because there is no way to express the relationship in most languages we’re using.

Here’s an example:

class A
{
  int Status { get; set; } = 0;
  like Status PriorStatus { get; }

  void Start(like Status s) {}
  void Stop(like Status s) {}
}

The syntax is similar to how ref and out work now, but looking at it takes a bit of getting used to, especially for the property declaration.

TypeScript has this feature, with the typeof operator, but they don’t name it. TypeScript has two advantages here: it places the type after the variable name, which feels a bit more natural when the type is expressed with multiple words, and TypeScript has implicit return types, so you don’t have to write the type at all in many cases.

Because of the implicit typing, TypeScript has technically had anchored types all along!

class A
{
    status: int = 0;

    // The implicit type here is derived from "status",
    // which "anchors" the type of the function to that field.
    get priorStatus() { return status; }

    // Here we're obliged to restrain the type explicitly
    void Start(s: typeof status) {}
    void Stop(s: typeof status) {}
}

As of TypeScript 4.7, it supports qualified anchored declarations on private fields as well.

Someone suggested in a response that generics might fill this bill already.

In a way, yes, that’s true. I could define the whole class with a generic type argument and then create a derived type that fixes the type argument to int.

class A<TStatus>
  where TStatus : INumber
{
  TStatus Status { get; set; } = TStatus.Zero;

  TStatus PriorStatus { get; }

  void Start(TStatus s) {}
  void Stop(TStatus s) {}
}

class IntA : A<int> {}

We have to use the newest features from C# 11 in order to be able to initialize the value to 0. If it were a value that maps to a non-mathematical concept (e.g. additive or multiplicative identity), then we wouldn’t be able to use the generic approach.

It feels a bit like misuse of generics, though, when I just wanted a shorthand for letting one type reference another. As I wrote, TypeScript already allows this and seems to have found it a useful addition to generics (you can probably implement it under-the-hood with the same code in the compiler).

I feel the same way about the missing type declaration from TypeScript (or the very similar, but less powerful typedef from C or Pascal).