Search code examples
typesd

Virtual static value types


Is it possible to create "virtual" value types for compile-time type safety and function overloading?

E.g. a greet function always takes a string, but based on which method produced the string, it would call the right variant.

I want to do this to simplify the API of a library. For example, instead of greetByFirstName and greetByLastName, I'd have just a greet method, something like this:

import std.array;
import std.format;
import std.stdio;

string firstName(string name) {
    return name.split(" ")[0];
}

string lastName(string name) {
    return name.split(" ")[1];
}

string greet(FirstName name) {
    return "Hi %s!".format(name);
}

string greet(LastName name) {
    return "Hello Mr. %s!".format(name);
}

unittest {
    string name = "John Smith";
    assert(firstName(name) == "John");
    assert(firstName(name).greet() == "Hi John!");
    assert(lastName(name).greet() == "Hello Mr. Smith!");
}

void main() {}

Solution

  • You can create a new type that has alias this to the base type, then overload on the more specific type. Alias this can be thought of as a way to do inheritance with structs, with implicit conversion back to a base "interface" type.

     // these are the new types
    struct FirstName { 
        string name; 
        alias name this; // this allows implicit conversion back to string when needed
    } 
    struct LastName { 
        string name; 
        alias name this; 
    } 
    FirstName firstName(string name) {  // these return the more specific  type
        return FirstName(name.split(" ")[0]); 
    } 
    LastName lastName(string name) { 
        return LastName(name.split(" ")[1]); 
    }  
    

    Now the rest of your code will work as needed, and you can still treat FirstName and LastName as strings when needed.