Difference between revisions of "Is expression"
(Added basic usage examples) |
m (correct forum link) |
||
(7 intermediate revisions by 3 users not shown) | |||
Line 1: | Line 1: | ||
{{DISPLAYTITLE:is expression}} | {{DISPLAYTITLE:is expression}} | ||
− | |||
"is" expressions are used for checking for valid types and are heavily used in template constraints. | "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: | The following are simple demonstrations of the "is" expression, distilled from the main site: | ||
Line 12: | Line 10: | ||
assert( !is(Foo) ); // Foo isnt a type, yet... | assert( !is(Foo) ); // Foo isnt a type, yet... | ||
struct Foo {} | struct Foo {} | ||
− | assert( is(Foo) ); | + | assert( is(Foo) ); // now it is |
short x = 1; | short x = 1; | ||
Line 38: | Line 36: | ||
===A More "Complex" Example === | ===A More "Complex" Example === | ||
− | A question was asked on [ | + | A question was asked on [https://forum.dlang.org the D forum] 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: |
− | |||
− | |||
− | 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: | ||
<source lang="D"> | <source lang="D"> | ||
Line 81: | Line 76: | ||
template isComplex(T) | template isComplex(T) | ||
{ | { | ||
− | static if ( is(T | + | static if ( is(T == Complex!CT, CT) ) { |
enum isComplex = true; | enum isComplex = true; | ||
} | } | ||
Line 93: | Line 88: | ||
== Summary == | == 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 [http://dlang.org/phobos/std_traits.html 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 | + | "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 [http://dlang.org/phobos/std_traits.html 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. |
+ | |||
+ | == External links == | ||
+ | * [http://dlang.org/spec/expression.html#IsExpression IsExpression] spec | ||
+ | * [http://ddili.org/ders/d.en/is_expr.html Programming in D - is Expression] | ||
+ | |||
+ | [[Category:Expressions]] |
Latest revision as of 05:06, 14 April 2024
"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 the D forum 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.