question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Strongly-typed type aliases

See original GitHub issue

I would love to see strongly-typed type aliases in the C# programming language. These would be roughly equivalent to types declared in Haskell using newtype. Such aliases would be very different from regular aliases declared using using statements since the source-level type would ultimately be erased by the compiler. However, they would behave as distinct types from the original type during compilation time.

I think this would be very helpful for dealing with easily abused types such as string. Here’s an example using a hypothetical new language structure using the newtype keyword:

using System;
newtype EmailAddress = System.String;

class Program
{
    static EmailAddress CreateEmailAddress(string text)
    {
        // Valid: use cast-style syntax to "convert" string to EmailAddress
        return (EmailAddress)text;
    }

    static void UseEmailAddress(EmailAddress emailAddress)
    {
        // Valid: everything has ToString
        Console.WriteLine(emailAddress);

        // Invalid: EmailAddress does not directly expose Length
        Console.WriteLine(emailAddress.Length);

        // Valid: EmailAddress instance can be explictly converted back to System.String
        // Does not result in runtime conversion since EmailAddress type is erased by
        // compiler
        Console.WriteLine(((string)emailAddress).Length);
    }

    static void Main()
    {
        // Valid
        UseEmailAddress(CreateEmailAddress("rcook@rcook.org"));

        // Invalid
        UseEmailAddress("rcook@rcook.org");
    }
}

This is purely syntactic sugar, however, and the compiler will emit all references to type EmailAddress as references to System.String instead. Perhaps some additional metadata could be applied to arguments of these alias types to provide a hint to compilers about the original (source-level) type assigned to it. There are obviously many questions that arise. The main one, I think, is what to do about methods that are declared on the original type: if they are all projected onto this new “virtual” type, then we lose all advantages of this new type safety. I believe that the compiler should prohibit the developer from calling any of the original type’s members on a reference to the alias type without inserting an explicit cast back to the underlying type. Such a cast would be purely syntactic and would not incur any runtime overhead.

In traditional C# programming, the developer would most likely wrap a string inside an EmailAddress wrapper class to ensure type safety and to curate access to the underlying string. My proposed language feature would enable the developer to more elegantly express certain concepts without bloating the code with wrapper classes. Importantly, it would also allow generation of extremely efficient code.

More issues:

  • What is the scope of a type declared with newtype?

Perhaps newtype could look more like the definition of a class or struct:

namespace MyNewtypeDemo
{
    using System;

    // No inheritance: this is an alias
    // Only methods declared inside the "newtype" declaration
    // can access the members of "string": no casting required
    // We'll reuse the contextual keyword "value"
    public newtype EmailAddress : string
    {
        // Constructor: can assign to "value" which is the actual string
        // Can only initialize via constructor
        public EmailAddress(string text)
        {
            if (!IsValidEmailAddress(text))
            {
                throw new ArgumentException();
            }

            // No cast required since compiler knows that "value" is a string
            value = text;
        }

        // Length is not normally accessible but we can wrap call to value.Length
        public int Length
        {
            get { return value.Length; }
        }

        public string ToActualString()
        {
            return value;
        }

        private static bool IsValidEmailAddress(string text)
        {
            // Validate text etc.
            return true;
        }
    }
}

Issue Analytics

  • State:closed
  • Created 9 years ago
  • Reactions:3
  • Comments:20 (9 by maintainers)

github_iconTop GitHub Comments

1reaction
maciascommented, Sep 17, 2022

@MadsTorgersen this is unfortunate (at least). How do you accomplish it with struct? Either I am missing something or you would have to constantly type something like wrapper.Value.

Anyway, it is 2022 and working with primitive types (like long, int) was a pain years ago and it is pain still. This is because I cannot differentiate that this long is id for nodes, and this long is id for roads, and this long… and so on. For C# they are all the same.

1reaction
rcookcommented, Jan 23, 2015

@svick

If this was the case, wouldn’t it mean that newtype saves you exactly one line of code (defining the private string value; field)? I don’t think that would be worth it.

Yes, you’re absolutely right. From a syntactic sugar standpoint, it doesn’t gain us much. However, my other interest in having such a language feature is in generating efficient runtime code. I’m happy to declare my newtype with syntax that is more or less the same as that of a struct or class. However, I want use of the objects of this type to incur as little overhead as possible over using a raw string. Essentially, I want type safety at compile time and minimal code overhead at runtime.

In many ways this is similar to some of the motivations behind enum types when a language implements them properly. These are essentially constrained integers. I want to be able to constrain strings, or any other type I can think of.

Some links of interest:

Read more comments on GitHub >

github_iconTop Results From Across the Web

Can I define my own "strong" type alias in Rust?
1 Answer. Rust has a nice trick called the New Type Idiom just for this. By wrapping a single item in a tuple...
Read more >
Is there a way to "strong type" aliases? : r/typescript
So no, it won't work. But you could do what the other comments suggest, add a unique property to each type to "tag"...
Read more >
type aliases - The Rust Programming Language
The type keyword lets you declare an alias of another type: ... In other words, because Rust is strongly typed, you'd expect a...
Read more >
Strong and weak typing
Smalltalk, Ruby, Python, and Self are all "strongly typed" in the sense that typing errors are prevented at runtime and they do little...
Read more >
Strongly typed language
We could also create type aliases, which generate alternative names — aliases — for known types. Note that type aliases are sometimes called...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found