See also: Programming in D for C Programmers
class Foo { Foo(int x); };
class Foo { this(int x) { } }which reflects how they are used in D.
class A { A() {... } }; class B : A { B(int x) : A() // call base constructor { ... } };
class A { this() { ... } } class B : A { this(int x) { ... super(); // call base constructor ... } }It's superior to C++ in that the base constructor call can be flexibly placed anywhere in the derived constructor. D can also have one constructor call another one:
class A { int a; int b; this() { a = 7; b = foo(); } this(int x) { this(); a = x; } }Members can also be initialized to constants before the constructor is ever called, so the above example is equivalently written as:
class A { int a = 7; int b; this() { b = foo(); } this(int x) { this(); a = x; } }
struct A x, y; ... x = y;it does not for struct comparisons. Hence, to compare two struct instances for equality:
#include <string.h> struct A x, y; inline bool operator==(const A& x, const A& y) { return (memcmp(&x, &y, sizeof(struct A)) == 0); } ... if (x == y) ...Note that the operator overload must be done for every struct needing to be compared, and the implementation of that overloaded operator is free of any language help with type checking. The C++ way has an additional problem in that just inspecting the (x == y) does not give a clue what is actually happening, you have to go and find the particular overloaded operator==() that applies to verify what it really does.
There's a nasty bug lurking in the memcmp() implementation of operator==(). The layout of a struct, due to alignment, can have 'holes' in it. C++ does not guarantee those holes are assigned any values, and so two different struct instances can have the same value for each member, but compare different because the holes contain different garbage.
To address this, the operator==() can be implemented to do a memberwise compare. Unfortunately, this is unreliable because (1) if a member is added to the struct definition one may forget to add it to operator==(), and (2) floating point nan values compare unequal even if their bit patterns match.
There just is no robust solution in C++.
A x, y; ... if (x == y) ...
#define HANDLE_INIT ((Handle)(-1)) typedef void *Handle; void foo(void *); void bar(Handle); Handle h = HANDLE_INIT; foo(h); // coding bug not caught bar(h); // okThe C++ solution is to create a dummy struct whose sole purpose is to get type checking and overloading on the new type.
#define HANDLE_INIT ((void *)(-1)) struct Handle { void *ptr; Handle() { ptr = HANDLE_INIT; } // default initializer Handle(int i) { ptr = (void *)i; } operator void*() { return ptr; } // conversion to underlying type }; void bar(Handle); Handle h; bar(h); h = func(); if (h != HANDLE_INIT) ...
typedef void *Handle = cast(void *)-1; void bar(Handle); Handle h; bar(h); h = func(); if (h != Handle.init) ...Note how a default initializer can be supplied for the typedef as a value of the underlying type.
class A { private: int a; public: int foo(B *j); friend class B; friend int abc(A *); }; class B { private: int b; public: int bar(A *j); friend class A; }; int A::foo(B *j) { return j->b; } int B::bar(A *j) { return j->a; } int abc(A *p) { return p->a; }
module X; class A { private: static int a; public: int foo(B j) { return j.b; } } class B { private: static int b; public: int bar(A j) { return j.a; } } int abc(A p) { return p.a; }The private attribute prevents other modules from accessing the members.
struct A { int operator < (int i); int operator <= (int i); int operator > (int i); int operator >= (int i); }; int operator < (int i, A &a) { return a > i; } int operator <= (int i, A &a) { return a >= i; } int operator > (int i, A &a) { return a < i; } int operator >= (int i, A &a) { return a <= i; }A total of 8 functions are necessary.
struct A { int opCmp(int i); }The compiler automatically interprets all the <, <=, > and >= operators in terms of the cmp function, as well as handling the cases where the left operand is not an object reference.
Similar sensible rules hold for other operator overloads, making using operator overloading in D much less tedious and less error prone. Far less code needs to be written to accomplish the same effect.
namespace Foo { int x; } using Foo::x;
---- Module Foo.d ------ module Foo; int x; ---- Another module ---- import Foo; alias Foo.x x;Alias is a much more flexible than the single purpose using declaration. Alias can be used to rename symbols, refer to template members, refer to nested class types, etc.
class File { Handle *h; ~File() { h->release(); } };
The few RAII issues left are handled by auto classes. Auto classes get their destructors run when they go out of scope.
auto class File { Handle h; ~this() { h.release(); } } void test() { if (...) { auto File f = new File(); ... } // f.~this() gets run at closing brace, even if // scope was exited via a thrown exception }
class Abc { public: void setProperty(int newproperty) { property = newproperty; } int getProperty() { return property; } private: int property; }; Abc a; a.setProperty(3); int x = a.getProperty();All this is quite a bit of typing, and it tends to make code unreadable by filling it with getProperty() and setProperty() calls.
class Abc { void property(int newproperty) { myprop = newproperty; } // set int property() { return myprop; } // get private: int myprop; }which is used as:
Abc a; a.property = 3; // equivalent to a.property(3) int x = a.property; // equivalent to int x = a.property()Thus, in D a property can be treated like it was a simple field name. A property can start out actually being a simple field name, but if later if becomes necessary to make getting and setting it function calls, no code needs to be modified other than the class definition. It obviates the wordy practice of defining get and set properties 'just in case' a derived class should need to override them. It's also a way to have interface classes, which do not have data fields, behave syntactically as if they did.
template<int n> class factorial { public: enum { result = n * factorial<n - 1>::result }; }; template<> class factorial<1> { public: enum { result = 1 }; }; void test() { printf("%d\n", factorial<4>::result); // prints 24 }
template factorial(int n) { enum { factorial = n* .factorial!(n-1) } } template factorial(int n : 1) { enum { factorial = 1 } } void test() { printf("%d\n", factorial!(4)); // prints 24 }