is expression

From D Wiki
Revision as of 11:38, 16 April 2016 by NickTreleaven (talk | contribs) (A More "Complex" Example: Remove unnecessary _ identifier)
Jump to: navigation, search

"is" expressions are used for checking for valid types and are heavily used in template constraints.

The following are simple demonstrations of the "is" expression, distilled from the main site:

import std.stdio;
void main()
{
    assert( !is(Foo) ); // Foo isnt a type, yet...
    struct Foo {}
    assert( is(Foo) ); // now it is

    short x = 1;
    assert( is(typeof(x) == short) );
    assert( is(typeof(x) :  int  ) ); // can be implicitly converted

    alias double MyDubble;
    void foo(MyDubble x) {
        static if( is(MyDubble T) ) {
            writeln("MyDubble is a double");
        }
    }
    // foo("hello"); // T is a string: fail
    foo(4.2);        // T is a double: pass

    alias real MyReal;
    void bar(MyReal y) {
        static if( is(MyReal T : float) ) {
            writeln("MyReal");
        }
    }
    bar(3); // can be implicitly converted
}

A More "Complex" Example

A question was asked on DForum learning channel about how to create a template that would accept any numeric type including complex types. This author (User:Jniehus) made several attempts to solve the poster's problem which "eventually" resulted in a final solution that looked like the following:

import std.stdio, std.conv, std.traits, std.complex;
template isComplex(T) {
    static if ( is(T == Complex!double) ) {
        enum bool isComplex = true;
    }
    else static if ( is(T == Complex!float) ) {
        enum bool isComplex = true;
    }
    else static if ( is(T == Complex!real) ) {
        enum bool isComplex = true;
    }
    else {
        enum bool isComplex = false;
    }
}

template isComplexOrNumeric(T) {
    enum bool isComplexOrNumeric = (isComplex!T || isNumeric!T);
}

class Example(T) if (isComplexOrNumeric!T) {
    T k = to!T(1);
}

void main() {
    auto x = new Example!(Complex!double)();
    writeln(x.k);
    auto y = new Example!double();
    writeln(y.k);
}

This unsightly "static if" chain was used because a Complex type is actually a template itself which can accept one of three primitive types; double, float, or real. But as a more experienced D programmer (Artur Skawina) pointed out, the "is" expression is flexible enough to accomodate situations like this. So instead of writing a "static if" statement for each possible template type, we can use the following syntax to infer the secondary types:

template isComplex(T) 
{
   static if ( is(T == Complex!CT, CT) ) {
      enum isComplex = true;
   }
   else {
      enum isComplex = false;
   }
}

This is clearly a more scalable solution.

Summary

"is" expressions might seem simple at first glance, but there is much more under the surface. The various forms of an "is" expression mean slightly different things, and knowing when and where to use them is important when writing templates. Also, familiarize yourself with std.traits, the most common type checks have already been done for you! If you want to see how they are done, browse the Phobos source for traits.d.