my.named_type

Members

Aliases

NamedTypeT
alias NamedTypeT(T, Traits...) = NamedType!(T, Tag!(T.stringof), T.init, Traits)
Undocumented in source.
Printable
alias Printable = TagStringable
Undocumented in source.

Enums

hasTraits
eponymoustemplate hasTraits(T, Traits...)
Undocumented in source.

Structs

Addable
struct Addable
Undocumented in source.
Arithmetic
struct Arithmetic
Undocumented in source.
Comparable
struct Comparable
Undocumented in source.
ConvertStringable
struct ConvertStringable

Uses std.conv.to!string to convert the underlying type to a string.

Decrementable
struct Decrementable
Undocumented in source.
Divisable
struct Divisable
Undocumented in source.
ForwardStringable
struct ForwardStringable

Forward to the underlying type the toString.

Hashable
struct Hashable
Undocumented in source.
ImplicitConvertable
struct ImplicitConvertable
Undocumented in source.
Incrementable
struct Incrementable
Undocumented in source.
Lengthable
struct Lengthable
Undocumented in source.
Modulable
struct Modulable
Undocumented in source.
Multiplicable
struct Multiplicable
Undocumented in source.
NamedType
struct NamedType(T, TagT = Tag!(T.stringof), T init = T.init, TraitsT...)
Undocumented in source.
Subtractable
struct Subtractable
Undocumented in source.
Tag
struct Tag(alias T)
Undocumented in source.
TagStringable
struct TagStringable
Undocumented in source.

Meta

Authors

Joakim Brännström (joakim.brannstrom@gmx.com)

This is inspired from NamedTypes C++.

A strong type is a type used in place of another type to carry specific meaning through its name. It is a variant of TypeDef in phobos

Basic usage

The central piece is the templated class NamedType, which can be used to declare a strong type with a typedef-like syntax:

alias Width = NamedType!(double, Tag!"width");
alias Height = NamedType!(double, Tag!"height");

which can be used to make interfaces more expressive and more robust. Note how the below constructor shows in which order it expects its parameters:

class Rectangle {
    private double width_;
    private double height_;

    this(Width width, Height height) {
        this.width_ = width.get;
        this.height_ = height.get;
    }

    double width() const { return width_; }
    double height() const { return height_; }
}

*Strong types are about better expressing your intentions, both to the compiler and to other human developers.**

Strong typing over generic types

This implementation of strong types can be used to add strong typing over generic or unknown types such as lambdas:

static bool performAction(T)(T x, T y) if(hasTraits!(T, Comparable)) {
    return x > y;
}

Inheriting the underlying type functionalities

You can declare which functionalities should be inherited from the underlying type. So far, only basic operators are taken into account. For instance, to inherit from + and toString, you can declare the strong type:

alias Meter = NamedType!(double, Tag!"meter", Addable, Printable);

There is one special trait, ImplicitConvertable, that lets the strong type be converted in the underlying type. This has the effect of removing the need to call .get() to get the underlying value.

Named arguments

By their nature strong types can play the role of named parameters:

alias FirstName = NamedType!(string, Tag!"firstName");
alias LastName = NamedType!(string, Tag!"lastName");

void displayName(FirstName theFirstName, LastName theLastName);

// Call site
displayName(FirstName("John"), LastName("Doe"));

But the nested type argument allows to emulate a named argument syntax:

alias FirstName = NamedType!(string, Tag!"firstName");
alias LastName = NamedType!(string, Tag!"lastName");

void displayName(FirstName theFirstName, LastName theLastName);

// Call site
displayName(FirstName.argument = "John", LastName.argument = "Doe");