kids encyclopedia robot

D (programming language) facts for kids

Kids Encyclopedia Facts
Quick facts for kids
D programming language
D Programming Language logo.svg
Paradigm Multi-paradigm: functional, imperative, object-oriented
Designed by Walter Bright, Andrei Alexandrescu (since 2007)
Developer D Language Foundation
First appeared 8 December 2001; 23 years ago (2001-12-08)
Stable release
2.111.0 Edit this on Wikidata / 1 April 2025; 4 months ago (1 April 2025)
Typing discipline Inferred, static, strong
OS FreeBSD, Linux, macOS, Windows
License Boost
Filename extensions .d, .di, .dd
Major implementations
DMD (reference implementation), GCC,

GDC,

LDC, SDC
Influenced by
BASIC, C, C++, C#, Eiffel, Java, Python, Ruby
Influenced
Genie, MiniD (since renamed Croc), Qore, Swift, Vala, C++11, C++14, C++17, C++20, Go, C#, others

D, also known as dlang, is a special kind of programming language that lets you build many different types of computer programs. It was created by Walter Bright in 2001. Later, Andrei Alexandrescu joined the team in 2007 to help design and develop it further.

D was first made to be a better version of C++. However, it has grown into a unique language. It has taken ideas from other popular languages like Java, Python, Ruby, C#, and Eiffel.

D is a general-purpose language. This means you can use it for many different tasks. It has a syntax (the way you write the code) that looks a lot like C. D programs are turned into native code, which means they run directly on your computer. It also helps manage computer memory, both automatically and manually.

What Makes D Programming Language Special?

D is not exactly like C or C++ in its code. But if you write code that works in C/C++ and D, it will usually do the same thing.

Key Features of D Language

D has many cool features. It includes closures (functions that remember their surroundings) and anonymous functions (functions without a name). It can also run some code while the program is being built, which is called compile-time function execution. D also helps you check your code with "design by contract." It has ways to loop through lists of items and can guess the type of data you are using.

Unlike C++, D also has garbage collection. This automatically cleans up unused memory. It also treats arrays as "first-class citizens," meaning they are very important. D lets you select parts of arrays, and you can even put functions inside other functions.

D uses a simpler way of inheritance (how classes get features from others). It uses "interfaces" and "mixins" instead of the more complex C++ style.

Low-Level Programming with D

D is a systems programming language. This means it can work very closely with your computer's hardware. Like C++, D allows low-level programming. You can even write inline assembler code directly in D. This lets programmers control the processor's features. It is useful for making operating systems or device drivers. It can also help make programs run super fast.

D lets you use the same function name for different tasks, which is called function overloading. You can also change how operators (like + or -) work for your own data types. This is called operator overloading. You can declare things in any order in D, so you don't need to say what's coming first.

In D, text strings are like lists of characters. Arrays in D are checked to make sure you don't try to access parts that don't exist. D also has special types for complex and imaginary numbers.

How D Supports Different Programming Styles

D supports five main ways of writing code:

  • Concurrent: For running many tasks at once.
  • Object-oriented: Using "objects" that combine data and actions.
  • Imperative: Giving the computer step-by-step instructions.
  • Functional: Using functions as the main building blocks.
  • Metaprogramming: Writing programs that write or change other programs.

Imperative Programming in D

Writing imperative code in D is very similar to C. Functions, data, and instructions work in the same way. You can even use C's standard library directly.

However, D has a special `foreach` loop. This makes it easier to go through items in a collection. D also lets you create nested functions. These are functions inside other functions that can use the outer function's local variables.

import std.stdio;

void main() {
   int multiplier = 10;
   int scaled(int x) { // This is a nested function
      return x * multiplier;
   }

   foreach (i; 0 .. 10) { // The foreach loop
      writefln("Hello, world %d! scaled = %d", i, scaled(i));
   }
}

This example shows a nested function `scaled` that uses `multiplier` from `main`. The `foreach` loop then uses `scaled`.

Object-Oriented Programming in D

Object-oriented programming in D is based on a single inheritance system. All classes (blueprints for objects) come from a main "Object" class. D does not allow "multiple inheritance" (getting features from many parent classes). Instead, it uses "interfaces" and "mixins." Interfaces are like contracts that classes must follow. Mixins let you add common features without complex inheritance.

D also lets you define special checks called "invariants" within classes. These checks run automatically before and after public methods. This helps ensure your code works as expected.

Many parts of classes can be checked automatically. This happens when the program is being built (compile time) or when it is running (run time). This helps create flexible code or code that generates itself.

Functional Programming in D

D supports functional programming. This includes function literals (functions without names) and closures. It also lets you use "recursively-immutable objects" (data that cannot be changed once created). D uses higher-order functions, which are functions that can take other functions as input or give them as output.

Here are two ways to write anonymous functions:

int function(int) g;
g = (x) { return x * x; }; // longhand
g = (x) => x * x;          // shorthand

The compiler can often figure out the type of an anonymous function. It will create a "delegate" if needed, which includes a pointer to the surrounding environment.

D's standard library has tools for other functional features. These include currying (breaking down functions) and common higher-order functions like map, filter, and reduce.

import std.stdio, std.algorithm, std.range;

void main() {
    int[] a1 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
    int[] a2 = [6, 7, 8, 9];

    // 'pivot' must be immutable to be used inside a pure function
    immutable pivot = 5;

    int mySum(int a, int b) pure nothrow /* pure function */ {
        if (b <= pivot) // refers to 'pivot' from outside
            return a + b;
        else
            return a;
    }

    // passing a delegate (closure)
    auto result = reduce!mySum(chain(a1, a2));
    writeln("Result: ", result); // Result: 15

    // passing a delegate literal
    result = reduce!((a, b) => (b <= pivot) ? a + b : a)(chain(a1, a2));
    writeln("Result: ", result); // Result: 15
}

This example shows how `reduce` can use a function (`mySum`) or an anonymous function to process a list of numbers.

You can also write these function calls in a more natural way, reading from left to right:

    auto result = a1.chain(a2).reduce!mySum();
    writeln("Result: ", result);

    result = a1.chain(a2).reduce!((a, b) => (b <= pivot) ? a + b : a)();
    writeln("Result: ", result);

Parallel Programming in D

D makes it easy to write programs that do many things at the same time. This is called parallel programming. D's type system and compiler help manage data sharing safely.

import std.stdio : writeln;
import std.range : iota;
import std.parallelism : parallel;

void main() {
    foreach (i; iota(11).parallel) {
        // This loop runs parts of its code at the same time
        writeln("processing ", i);
    }
}

The `iota(11).parallel` part tells the program to run the loop's body in parallel for each number.

D also has `taskPool` for creating parallel tasks. This is useful for operations like map, filter, and reduce on lists. For example, `std.algorithm.map` creates a "lazy" list. This means elements are calculated only when needed, and worker tasks can compute them in parallel.

Concurrency in D

Concurrency is about managing multiple tasks that might run at the same time. D's library fully supports this. It does not need special compiler features. D's typing system helps make sure memory is used safely when tasks run together.

import std.stdio, std.concurrency, std.variant;

void foo() {
    bool cont = true;

    while (cont) {
        receive( // Delegates help match the message type.
            (int msg) => writeln("int received: ", msg),
            (Tid sender) { cont = false; sender.send(-1); },
            (Variant v) => writeln("huh?") // Variant matches any type
        );
    }
}

void main() {
    auto tid = spawn(&foo); // Starts a new thread running foo()

    foreach (i; 0 .. 10)
        tid.send(i);   // Sends some integers

    tid.send(1.0f);    // Sends a float
    tid.send("hello"); // Sends a string
    tid.send(thisTid); // Sends a struct (Tid)

    receive((int x) => writeln("Main thread received message: ", x));
}

This example shows how different parts of a program can send messages to each other.

Metaprogramming in D

Metaprogramming means writing programs that can create or change other programs. D supports this using "templates," "compile-time function execution," "tuples," and "string mixins."

Here's a function that calculates the factorial of a number:

ulong factorial(ulong n) {
    if (n < 2)
        return 1;
    else
        return n * factorial(n-1);
}

You can also do this calculation using a template. This uses `static if`, which is D's way of making decisions when the program is being built:

template Factorial(ulong n) {
    static if (n < 2)
        enum Factorial = 1;
    else
        enum Factorial = n * Factorial!(n-1);
}

You can use these to calculate factorials. The compiler can figure out the types of constants for you:

enum fact_7 = Factorial!(7);

D also allows "compile-time function execution" (CTFE). This means ordinary functions can run when the program is being built, if they follow certain rules:

enum fact_9 = factorial(9);

The `std.string.format` function helps format data, even at compile time. The "msg" pragma then shows the result during the build process:

import std.string : format;
pragma(msg, format("7! = %s", fact_7));
pragma(msg, format("9! = %s", fact_9));

"String mixins" let you create D code using text operations when the program is being built. This is useful for building special languages that become part of your program.

How D Manages Memory

Memory in D is usually managed automatically by garbage collection. This system finds and cleans up memory that is no longer being used. Most D programs and libraries use this method.

If you need more control or better performance, you can manage memory yourself. You can use special operators like `new`, or call C's `malloc` and `free` functions directly. You can also create your own memory management systems. You can even tell the garbage collector to ignore certain parts of memory or force it to clean up.

In functions, `struct` instances (like small data containers) are usually stored on the "stack" (a temporary memory area). `class` instances (objects) are usually stored on the "heap" (a more flexible memory area). However, you can change this if needed.

Static arrays (arrays with a fixed size) are also stored on the stack. For dynamic arrays (arrays that can change size), you can use `core.stdc.stdlib.alloca` to put them on the stack.

The `scope` keyword can mark parts of code or variables. It tells the program to clean them up as soon as they are no longer needed.

SafeD: Keeping Your Code Safe

SafeD is a part of D that helps ensure your code is memory safe. Functions marked `@safe` are checked when the program is built. This makes sure they don't use features that could corrupt memory, like direct pointer math. Any other functions called must also be `@safe` or `@trusted`. Functions can be `@trusted` if the compiler can't tell if a feature is safe or not, but you know it is.

Protecting Data Lifetimes

D has ways to protect against problems with how long data exists in memory. This mainly deals with function inputs and stack memory. The goal is to make sure data doesn't disappear while your program still needs it.

Checking Assignments for Safety

In `@safe` code, D checks assignments involving "reference types" (variables that point to other data). It makes sure that the data you are pointing to will last longer than the variable itself.

For example:

@safe void test() {
    int tmp = 0; // #1
    int* rad;    // #2
    rad = &tmp;  // This works.
    {
        int bad = 45; // 'bad' only exists inside these curly brackets.
        *rad = bad;   // This is okay.
        rad = &bad;   // This is NOT okay because 'rad' will last longer than 'bad'.
    }
}

Function Parameter Lifetime Rules

When you add `return` or `scope` to function parameters (inputs), it controls how long that data can be used.

  • `scope`: Means the data cannot leave the function.
  • `return`: Means the data can be returned by the function, but it won't last longer than the original input.

Here's an example:

@safe:

int* gp;
void thorin(scope int*);
void gloin(int*);
int* balin(return scope int* p, scope int* q, int* r) {
     gp = p; // Error: 'p' cannot escape to a global variable.
     gp = q; // Error: 'q' cannot escape to a global variable.
     gp = r; // OK: 'r' can escape.

     thorin(p); // OK: 'p' does not escape thorin().
     thorin(q); // OK.
     thorin(r); // OK.

     gloin(p); // Error: 'p' escapes gloin().
     gloin(q); // Error: 'q' escapes gloin().
     gloin(r); // OK: 'r' can escape gloin().

     return p; // OK: 'p' can be returned.
     return q; // Error: cannot return 'scope' q.
     return r; // OK: 'r' can be returned.
}

How D Works with Other Systems

D can work well with code written in other languages. It supports C's way of connecting programs, so you can use existing C code and libraries directly. Many D programs use popular C libraries. C's standard library is also part of D.

On Windows computers, D can connect with Component Object Model (COM) code.

D can also be mixed with many other languages in one program. For example, the GDC compiler lets you combine D, C, C++, and even Objective-C code. D functions can also be set up to work with C, C++, or Pascal programs. This means data can be shared between these languages.

Because many other programming languages offer a C connection for extensions, D can talk to them directly. For example, D has connections for Python and Lua.

Working with C++ Code

D code can also work with C++ code. When D code is marked `extern(C++)`, it means it will follow C++ rules for naming and function calls.

An Example of D and C++ Working Together

The C++ side

import std;

class Base {
    public:
        virtual void print3i(int a, int b, int c) = 0;
};

class Derived : public Base {
    public:
        int field;
        Derived(int field): 
            field(field) {}

        void print3i(int a, int b, int c) {
            std::println("a = {}", a);
            std::println("b = {}", b);
            std::println("c = {}", c);
        }

        int mul(int factor);
};

int Derived::mul(int factor) {
    return field * factor;
}

Derived* createInstance(int i) {
    return new Derived(i);
}

void deleteInstance(Derived*& d) {
    delete d;
    d = 0;
}

The D side

extern(C++) {
    abstract class Base {
        void print3i(int a, int b, int c);
    }

    class Derived : Base {
        int field;
        @disable this();
        override void print3i(int a, int b, int c);
        final int mul(int factor);
    }

    Derived createInstance(int i);
    void deleteInstance(ref Derived d);
}

void main() {
    import std.stdio;

    auto d1 = createInstance(5);
    writeln(d1.field);
    writeln(d1.mul(4));

    Base b1 = d1;
    b1.print3i(1, 2, 3);

    deleteInstance(d1);
    assert(d1 is null);

    auto d2 = createInstance(42);
    writeln(d2.field);

    deleteInstance(d2);
    assert(d2 is null);
}

This example shows how D code can create and use objects defined in C++.

Better C: A Simpler D

D has a special version called "Better C." This version limits D to features that work like C. It means you can only use D features that don't need D's own special runtime libraries.

You can turn on Better C using compiler flags like "-betterC". Code compiled with Better C can only call other Better C code. However, regular D code can call Better C code.

What Better C Includes

  • You can use all of D's compile-time features.
  • It has full metaprogramming tools.
  • You can use nested functions, structs, delegates, and lambdas.
  • It supports member functions, constructors, and operator overloading.
  • It has the full module system.
  • You can slice arrays and it checks array boundaries.
  • It supports RAII (Resource Acquisition Is Initialization).
  • It includes `scope(exit)` for cleanup.
  • It has memory safety protections.
  • It can connect with C++ code.
  • It supports COM classes and C++ classes.
  • `assert` failures go to the C runtime library.
  • You can use `switch` statements with strings.
  • It has `final switch` and `unittest` blocks.
  • It validates `printf` formats.

What Better C Excludes

  • Automatic garbage collection.
  • TypeInfo and ModuleInfo (information about types and modules).
  • Built-in threading features.
  • Dynamic arrays (arrays that can change size) and associative arrays (like dictionaries).
  • Exceptions (a way to handle errors).
  • `synchronized` and `core.sync` (for managing shared resources).
  • Static module constructors or destructors.

History of D Programming Language

Walter Bright started creating D in 1999. The first version, D1, came out in December 2001. It focused on imperative, object-oriented, and metaprogramming styles.

For a while, there were two main standard libraries for D: Phobos (the official one) and Tango (a community-made one). They were not compatible, which caused some issues.

In June 2007, D2 was released. This new version brought big changes, like a new system for `const` (constant) values. D2 also added many new features, such as closures, purity, and support for functional and concurrent programming. D2 also fixed the library problems by separating the runtime from the standard library.

In June 2010, Andrei Alexandrescu's book The D Programming Language was published. This showed that D2 was stable and ready for widespread use. Today, D2 is simply called "D."

In January 2011, D's development moved to GitHub. This made it easier for many people to help improve the compiler and libraries.

D1, the first version of the language, was officially stopped on December 31, 2012.

The official D compiler, DMD, was originally under a special license. In 2014, parts of it became open source under the Boost Software License. By April 2017, the entire compiler was open source. In June 2017, the D Language was accepted into GCC, a major set of compilers.

How D Programs Are Built

Most D programs are compiled directly into machine code. This means they are turned into instructions that your computer's processor can understand and run.

Main D Compilers

  • DMD: This is the official D compiler by Walter Bright. It's open source. Parts of it are now written in D itself. It supports 32-bit and 64-bit computers.
  • GCC: The GNU Compiler Collection now includes D. This means D can be used on many different computer systems.
  • LDC: This compiler uses the DMD front-end but uses LLVM for its back-end. It was first released in 2009.

Other D Compilers (for learning or special uses)

  • D Compiler for .NET: This compiler turns D code into CIL bytecode, which can run on a Common Language Infrastructure (CLI) virtual machine. This project is no longer actively updated.
  • SDC: The Snazzy D Compiler is written in D and uses LLVM. It supports a smaller part of the D language.

Using these compilers, D programs can run on many different computer architectures. These include IA-32, amd64, AArch64, and more. D works on Windows, Linux, Mac OS X, FreeBSD, and other operating systems. D can even be compiled for WebAssembly, which lets it run in web browsers.

Tools for D Development

Many tools help programmers write D code. These include text editors and integrated development environments (IDEs). They offer features like syntax highlighting (coloring code to make it easier to read) and code completion (suggesting code as you type).

Some popular tools include:

  • Dexed: A D-focused graphical IDE.
  • Mono-D: A full-featured IDE based on MonoDevelop.
  • Eclipse plug-ins: DDT and Descent.
  • Visual Studio integration: Provided by VisualD.
  • Visual Studio Code extensions: Dlang-Vscode or Code-D.
  • TextMate and Code::Blocks have some support.
  • Xcode 3 plugin "D for Xcode."
  • KDevelop has an autocompletion plugin.
  • Dlang IDE: A cross-platform IDE written in D.

You can debug D applications using C/C++ debuggers like GNU Debugger (GDB) or WinDbg. There are also D-specific debuggers like Ddbg and ZeroBUGS.

DustMite is a tool that helps make D code smaller. This is useful for finding problems in compilers or tests.

dub is a popular tool for managing D projects and libraries. It helps organize code and build programs.

Where D Programming Language is Used

Many well-known organizations use the D programming language for their projects. These include Facebook, eBay, and Netflix.

D has been used for many different kinds of software:

A hacking group called Lazarus Group used D to create some of their malware programs.

Challenges for D Language

Some people who have worked with D have talked about challenges in getting changes and fixes into the language. This has sometimes made it hard to predict when improvements would happen. Because of these concerns, a new version called OpenD was started on January 1, 2024.

See also

Kids robot.svg In Spanish: D (lenguaje de programación) para niños

  • D Language Foundation
kids search engine
D (programming language) Facts for Kids. Kiddle Encyclopedia.