views:

1888

answers:

15

Continuing on the hidden features meme, I'd like to ask, what are the lesser-known features of the D programming language that every D user should know about?

Some related program language "hidden features" questions:

To kick it off, Don Clugston noted that some of these Easter Eggs may qualify as good "hidden features" to know.

+4  A: 

Maybe not so hidden but Array Slicing is pretty nifty.

http://en.wikipedia.org/wiki/Array_slicing#1999:_D

Ace
+12  A: 

This is a little .tupleof trick I find nifty, though I have to admit I haven't actually used it all that much:

Say you have a function:

setPosition(float x, float y, float z);

And you have a Point struct:

struct Point { float x; float y; float z; }

And a Point variable called m_currentPos. Now you want to call setPosition with the variable as the argument. Instead of explicitly dereferencing each component, you can just do:

setPosition(m_currentPos.tupleof);

which is equivalent to typing out:

setPosition(m_currentPos.x, m_currentPos.y, m_currentPos.z);
Baxissimo
why can't you just have an overload called setPosition(Point p) that does it for you?
Beh Tou Cheh
Yeah, like `void setPosition(Point p){setPosition(p.tupleof);}` Oh, wait, tupleof was still useful.
0scar
+5  A: 

One important difference between C/C++ and D is the way D treats pointers and arrays as part of type. I think this is a major improvement but developers need to be very aware of this to avoid problems.

In D to declare 2 char pointers you do:

char* chp1, chp2;

In C it's done like this:

char *chp1, *chp2;

Another example in C:

int *p, q, t[3], *s;

And in D:

int* p, s;
int q;
int[3] t;

This can be a hidden problem to new D devs, porting from c especially but once understood its a cool clean feature.

Tim Matthews
+2  A: 

not hidden but a "nifty feature":
array copying:

arr2[] = arr1[];
hasen j
This is cool. Also, you could do `arr2[] = arr1[] * 8` to scale an entire array. The manual states "many [of these vector operations] take advantage of any vector math instructions available on the target computer." Nice.
0scar
+3  A: 

The one thing that I personally consider the "niftiest" Hidden Feature is variable declaration in if expressions - i.e.

 import tools.base;
 void main() {
   auto test = "test foo";
   if (auto rest = test.startsWith("test "))
     assert(rest == "foo");
  }

This can also be used to simplify casts.


   class A { }
   void main() {
     Object obj = new A;
     if (auto obj_as_a = cast(A) obj) {
       // ...
     }
   }
FeepingCreature
+3  A: 

The struct/tuple duality is pretty useful. For example, here's a generic comparison function for structs. This is useful if you need a total ordering among a bunch of structs, but it doesn't matter exactly how that total ordering is defined, such as for placing them in some kind of binary tree. It works by treating the elements of the struct as representing place value, i.e. compare the first element first, if equal, break tie with second element, etc. Note that this will only work in recent versions of D2.

enum CompareStructs = "
    int opCmp(const typeof(this) rhs) {
        foreach(ti, elem; this.tupleof) {
            if(elem < rhs.tupleof[ti]) {
                return -1;
            } else if(elem > rhs.tupleof[ti]) {
                return 1;
            }
        }
        return 0;
    }
    ";

struct Foo {
    uint first;
    uint second;

    mixin(CompareStructs);
}

void main() {  // Test it out.
    Foo small = Foo(1, 2);
    Foo large = Foo(2, 1);

    assert(small < large);
    assert(large > small);
}
dsimcha
+2  A: 

This is a nifty static if trick I picked up recently (I think I saw it first in some of Andrei's code).

The situation is that you want to check at compile time if some bit of code is valid or not. Say you want to know if type T supports concatenation by type S using the ~= operator. Bascially you want to know if this will compile or not:

T x;
S y;
x ~= y;

The cool trick is to just put that code in an anonymous delegate and use typeof to see if it compiles.

static if (is(typeof({T x; S y; x~=y;}))) {
    /* do something */ 
}
else {
    /* do something else */
}

If it compiles, the typeof() will return void delegate() and is() will be true, if it doesn't compile then the tyepof will be invalid and is() will return false.

You can also use .init to avoid making variable names:

static if (is(typeof({T.init~=S.init;}))) {
    /* do something */ 
}
else {
    /* do something else */
}

Note that this is primarily for D1. In D2 there's __traits(compiles, T.init ~= S.init).

Baxissimo
A: 
zkp0s
I'd upvote is this had been broken in to several answers
caspin
+5  A: 

My favorites are some of the simpler language conceits to make life a little easier. For example, the ability to group the digits of numeric literals using the _ character:

int x = 65_536;

Also, the existence of nesting block comments (using /+ +/), specifically for commenting out code:

/+++++
/*
 * comment
 * comment
 */
 statement;
 statement;
+++++/
Tim Keating
+1  A: 

this is a nice trick if you have problems with array declarations, but you know how you would like to write it when using it.

for example if you would like to use something as complicated as

[["foo"[]: "bar"[]]: 5]

you can put a quick pragma in your code and compiler will output a declaration you need to use:

pragma(msg, typeof([["foo"[]: "bar"[]]: 5]).stringof);

this will output:

int[char[][char[]]]
Keyframe
+6  A: 

D has a great template system. It includes constraints which are the D equivalent of the dropped C++0x concepts.

D's templates can do a lot but what really 'puts the icing on the cake' and is not very well know is that D supports CTFE (Compile Time Function Execution).

See these 2 links for more info:
en.wikipedia.org
www.digitalmars.com

Tim Matthews
Wish I could upvote twice. This feature is unexpected and incredibly useful. Perfect hidden feature.
caspin
A: 

String literals.

Besides the well known "abc" and `abc`, there is also

  • Hex string literals (this means "\x12\x34\x56\xab\xcd\xef"):

.

x"12 3456ab cdef"
  • Delimited strings

.

q"/<a\s+href=(["'])(.*?)\1/"
  • Token strings (where the content must be valid D tokens)

.

q{x*x-x+1}
KennyTM
I've just started getting into D and admittedly haven't read much code yet, but what are token strings good for? Helping to eliminate syntax errors when using mixins?
shambulator
A: 

I think the power of lazy evaluation is many times ignored. An example (D 1.0):

import std.stdio;


int sum(ref int var, int first, int last, lazy int f)
{
    int result = 0;

    for (var = first; var <= last; var++)
    {
        result += f();
    }

    return result;
}


void main()
{
    int i;

    writefln(sum(i, 1, 10, i * i));
}

Which prints out: 385

Of course there are other ways to achieve the same result, but this example should give you a hint on how lazy evaluation can be used.

Pedro Rodrigues
+1  A: 

It supports the shebang!
(aka hashbang, hashpling, pound bang, or crunchbang [wikipedia])

shebang.d:

#!/usr/bin/env dmd -run
import std.stdio;
int main(string[] args){
        writefln("omg!");
        return 0;
}

And then

% chmod +x shebang.d
% ./shebang.d
omg!
% _
0scar
+1  A: 

Faked multiple inheritance using composition and alias this:

import std.stdio;

class A {
    int a;  
}

class B {
    int b;
}

class C : A {

    private B _b;
    int c;
    alias _b this;

    this()  {
        _b = new B();
    }
}

void main(string[] args) {
    auto c = new C();
    c.a = 5;
    c.b = 6;
    c.c = 7;
    writeln(c.a, " ", c.b, " ", c.c);
}
Corbin March